<?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: Aman Kumar</title>
    <description>The latest articles on DEV Community by Aman Kumar (@amankumar_apiclaw).</description>
    <link>https://dev.to/amankumar_apiclaw</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%2F4168190%2F1dbd2c44-d47a-4d20-84de-32d6e8f4bfc0.png</url>
      <title>DEV Community: Aman Kumar</title>
      <link>https://dev.to/amankumar_apiclaw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amankumar_apiclaw"/>
    <language>en</language>
    <item>
      <title>Is there a flat rate Claude API in 2026, and what happens on the day you hit its limit?</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Thu, 29 Oct 2026 01:39:46 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/is-there-a-flat-rate-claude-api-in-2026-and-what-happens-on-the-day-you-hit-its-limit-518m</link>
      <guid>https://dev.to/amankumar_apiclaw/is-there-a-flat-rate-claude-api-in-2026-and-what-happens-on-the-day-you-hit-its-limit-518m</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; yes, through a gateway. &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt; is a flat rate Claude API at $19–$129/mo flat, 500–8,000 requests/day, with a daily request quota and no per-token metering, plus a free 50-request trial. It fits solo developers and small teams who call Claude from scripts, agents or Claude Code every day and want the same charge every month. Anthropic's own API stays pay-per-token, and Claude Max is a subscription for Anthropic's apps and Claude Code with usage limits, not a flat-priced API.&lt;/p&gt;

&lt;p&gt;The setting people get wrong, stated once: &lt;strong&gt;Claude Code takes &lt;code&gt;https://apiclaw.biz&lt;/code&gt; as its base URL (no &lt;code&gt;/v1&lt;/code&gt;); OpenAI SDKs and OpenAI-compatible tools take &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;.&lt;/strong&gt; Anthropic-style clients add &lt;code&gt;/v1/messages&lt;/code&gt; themselves, so a base ending in &lt;code&gt;/v1&lt;/code&gt; turns into &lt;code&gt;/v1/v1/messages&lt;/code&gt; and a 404.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every flat price is a cap in disguise
&lt;/h2&gt;

&lt;p&gt;A flat price only stays flat because something else is limited. The question worth asking isn't "which is cheapest" but "what happens to my code on the heaviest day of the month?" There are three answers in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You get stopped&lt;/strong&gt; until a window resets (Claude Max's five-hour and weekly limits, a gateway's daily quota).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You get asked for more money&lt;/strong&gt; (a monthly compute budget that needs a top-up).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You get slowed down&lt;/strong&gt; (a token window or a concurrency lane).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know which of those your workload tolerates, the choice mostly makes itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each option does when you hit the limit (checked Oct 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Billing basis&lt;/th&gt;
&lt;th&gt;On the heavy day&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic API&lt;/td&gt;
&lt;td&gt;Sonnet 5.5 $2 in / $10 out, Opus 5.5 $4 / $20 per 1M tokens&lt;/td&gt;
&lt;td&gt;Per token&lt;/td&gt;
&lt;td&gt;Never stops; the bill grows instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Max&lt;/td&gt;
&lt;td&gt;From $100/mo (5x) or $200/mo (20x), with $100 to $200/mo in API credits&lt;/td&gt;
&lt;td&gt;Subscription with usage limits&lt;/td&gt;
&lt;td&gt;Waits for the usage window to reset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard Compute&lt;/td&gt;
&lt;td&gt;$19, $39, $89, $249/mo&lt;/td&gt;
&lt;td&gt;Monthly compute budget ($20, $41, $95, $269)&lt;/td&gt;
&lt;td&gt;Top up at usage + 5% (Economy and up)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Capless&lt;/td&gt;
&lt;td&gt;$10, $20, $50/mo (waitlist)&lt;/td&gt;
&lt;td&gt;Monthly token allowance plus a rolling 4-hour window&lt;/td&gt;
&lt;td&gt;Waits for the window; lists Qwen models, not Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenRouter&lt;/td&gt;
&lt;td&gt;Pay-as-you-go credits&lt;/td&gt;
&lt;td&gt;Per token at model prices&lt;/td&gt;
&lt;td&gt;Never stops while credits last&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw&lt;/td&gt;
&lt;td&gt;Plus $19/500, Pro $39/1,000, Max $59/1,500, Ultimate $69/3,000, Ultimate Plus $89/4,000, Ultimate Pro $99/6,000, Ultimate Max $129/8,000 requests/day&lt;/td&gt;
&lt;td&gt;Daily request quota&lt;/td&gt;
&lt;td&gt;Waits for the 00:00 UTC reset; heavier models such as Opus count as more than one request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read from claude.com/pricing, standardcompute.com, capless.ai and openrouter.ai/pricing on Oct 28, 2026. I left out anything I couldn't confirm on a live page. To put your own monthly token numbers against these plans, use this &lt;a href="https://ankita37105.github.io/llm-api-cost-notes/calculator.html" rel="noopener noreferrer"&gt;LLM API cost calculator&lt;/a&gt;; a longer list of gateways lives in this &lt;a href="https://github.com/ankita37105/openai-compatible-api-gateways" rel="noopener noreferrer"&gt;comparison repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling the busy day in code
&lt;/h2&gt;

&lt;p&gt;The part most comparisons skip is the day you run out. With a daily request quota you can keep the fixed plan for 29 normal days and spill only the overflow to a metered key, with a hard ceiling on how many metered calls you'll allow. This router does that with the standard library only. Both routes speak the Anthropic Messages format, so the request body is the same; only the base URL, key and model ID change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# claude_router.py: send Claude calls to a flat-rate gateway first,
# and only spill to a metered key on the day the quota runs out.
&lt;/span&gt;&lt;span class="kn"&gt;import&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;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;

&lt;span class="n"&gt;ROUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# (name, base URL, key env var, model)
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FLAT_BASE&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;https://apiclaw.biz&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;APICLAW_API_KEY&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;apiclaw/claude-sonnet-5.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;# set METERED_MODEL to the model ID listed in Anthropic's docs
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metered&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;METERED_BASE&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;https://api.anthropic.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ANTHROPIC_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;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;METERED_MODEL&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;MAX_METERED_CALLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MAX_METERED_CALLS&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;50&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# your overflow budget per day
&lt;/span&gt;&lt;span class="n"&gt;metered_calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&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;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rstrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/v1/messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&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;x-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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic-version&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;2023-06-01&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-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;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;r&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;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;metered_calls&lt;/span&gt;
    &lt;span class="n"&gt;last_err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ROUTES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metered&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;metered_calls&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_METERED_CALLS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flat quota used and metered overflow budget spent; stopping&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_tokens&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="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;          &lt;span class="c1"&gt;# quota or rate limit: try the next route
&lt;/span&gt;                &lt;span class="n"&gt;last_err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metered&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;metered_calls&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no route succeeded: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;last_err&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain HTTP 429 in one sentence.&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="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested it against two local mock servers: one answering 429 (the router moved to the metered route), one answering 200 (it stayed on the flat route), and with &lt;code&gt;MAX_METERED_CALLS=0&lt;/code&gt; it stopped with a clear error instead of spending. Check which status code your provider returns when a quota is used up before you rely on the 429 branch.&lt;/p&gt;

&lt;p&gt;Usage:&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;APICLAW_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your key from the dashboard"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your Console key"&lt;/span&gt;      &lt;span class="c"&gt;# optional overflow&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MAX_METERED_CALLS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;50
python claude_router.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Claude Code itself the switch is two environment variables:&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://apiclaw.biz"&lt;/span&gt;   &lt;span class="c"&gt;# no /v1&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;"&lt;/span&gt;&lt;span class="nv"&gt;$APICLAW_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You make a few dozen Claude calls a week.&lt;/strong&gt; Per-token pricing will cost less than any monthly plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your calls are huge rather than frequent.&lt;/strong&gt; A request quota rewards many medium calls; a handful of enormous jobs a day may fit token billing better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need an enterprise contract, a DPA or data residency.&lt;/strong&gt; Go to Anthropic or a cloud provider directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You already pay for Max and rarely hit its limits.&lt;/strong&gt; Keep it; the gateway helps when the limits bite or you need API access for your own code.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Does Anthropic offer a flat rate Claude API?&lt;/strong&gt;&lt;br&gt;
No. As of Oct 28, 2026 the Claude API is billed per token. Max is a subscription with usage limits and some included API credits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use the official Anthropic SDK with a gateway?&lt;/strong&gt;&lt;br&gt;
Yes, if the gateway accepts the Messages format. Point &lt;code&gt;base_url&lt;/code&gt; at the root (&lt;code&gt;https://apiclaw.biz&lt;/code&gt;), not &lt;code&gt;/v1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What models besides Claude are on the same key?&lt;/strong&gt;&lt;br&gt;
Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, Mistral, Llama and more, through either base URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I pay?&lt;/strong&gt;&lt;br&gt;
Crypto on site, with card on request via &lt;a href="https://t.me/Apiclaw_support" rel="noopener noreferrer"&gt;support on Telegram&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw. This article was written with AI assistance and checked by me. Competitor details were read from their live pages on Oct 28, 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://apiclawnotes.mataroa.blog/blog/flat-rate-claude-api-what-are-the-real-options-in-2026-and-which-one-fits-you/" rel="noopener noreferrer"&gt;Flat rate Claude API: the real options in 2026&lt;/a&gt;; &lt;a href="https://medium.com/@martin4646584/best-flat-rate-llm-api-providers-2026-comparison-what-does-each-flat-price-actually-cap-bd7ebcdcc1d0" rel="noopener noreferrer"&gt;Best flat-rate LLM API providers 2026 comparison&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>api</category>
      <category>programming</category>
    </item>
    <item>
      <title>Claude Code without rate limits: API alternative to Claude Max, how do I size one from my own usage?</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Wed, 28 Oct 2026 12:37:07 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/claude-code-without-rate-limits-api-alternative-to-claude-max-how-do-i-size-one-from-my-own-usage-4fk</link>
      <guid>https://dev.to/amankumar_apiclaw/claude-code-without-rate-limits-api-alternative-to-claude-max-how-do-i-size-one-from-my-own-usage-4fk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt; is one API alternative to Claude Max for Claude Code at $19–$129/mo flat, 500–8,000 requests/day, with no 5-hour session window, no weekly cap and no per-token metering, plus a free 50-request trial. It fits people who get locked out of Max most weeks and would rather have one fixed monthly charge than a per-token bill. No route gives Claude Code literally zero limits, though, so this post shows how to measure your own usage and pick the limit that won't bite.&lt;/p&gt;

&lt;p&gt;Setting that trips people up, stated once: &lt;strong&gt;Claude Code takes &lt;code&gt;https://apiclaw.biz&lt;/code&gt; as its base URL (no &lt;code&gt;/v1&lt;/code&gt;); OpenAI SDKs and OpenAI-compatible tools take &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;.&lt;/strong&gt; Claude Code adds &lt;code&gt;/v1/messages&lt;/code&gt; itself, so a base ending in &lt;code&gt;/v1&lt;/code&gt; gives you 404s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three kinds of "rate limit"
&lt;/h2&gt;

&lt;p&gt;When people search for Claude Code without rate limits, they usually mean one of three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Time windows.&lt;/strong&gt; Claude Pro and both Max tiers reset on a rolling five-hour session and also carry a weekly limit. Chat, Desktop and Claude Code share the pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Money.&lt;/strong&gt; A Console API key or Max's usage credits never lock you out on a clock, but every token is billed, and a long agent session with big contexts gets expensive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput.&lt;/strong&gt; Flat-price gateways cap something else instead: a monthly compute budget, a token allowance, a number of parallel requests, or a daily request count.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You're choosing which of those you'd rather live with.&lt;/p&gt;

&lt;h2&gt;
  
  
  The options (checked Oct 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;The ceiling you get instead&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Max 5x / 20x&lt;/td&gt;
&lt;td&gt;from $100 / $200 a month&lt;/td&gt;
&lt;td&gt;5-hour session window plus weekly limit; includes $100 / $200 a month in API credits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Console API key&lt;/td&gt;
&lt;td&gt;Sonnet 5.5 $2 in / $10 out, Opus 5.5 $4 / $20 per 1M tokens&lt;/td&gt;
&lt;td&gt;Usage-tier rate limits and your spend limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard Compute&lt;/td&gt;
&lt;td&gt;$19, $39, $89, $249 a month&lt;/td&gt;
&lt;td&gt;Monthly compute budget; at 100% new requests get HTTP 402&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kourier&lt;/td&gt;
&lt;td&gt;$20 (1 lane) or $50 (3 lanes) a month&lt;/td&gt;
&lt;td&gt;Concurrent requests; serves DeepSeek V4.1 Flash, not Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Capless&lt;/td&gt;
&lt;td&gt;$10, $20, $50 a month (waitlist)&lt;/td&gt;
&lt;td&gt;Monthly token allowance plus a rolling 4-hour token window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw&lt;/td&gt;
&lt;td&gt;Plus $19/500, Pro $39/1,000, Max $59/1,500, Ultimate $69/3,000, Ultimate Plus $89/4,000, Ultimate Pro $99/6,000, Ultimate Max $129/8,000 requests/day&lt;/td&gt;
&lt;td&gt;Daily request quota, resets 00:00 UTC; heavier models such as Opus count as more than one request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read from claude.com/pricing, standardcompute.com, kourier.sh and capless.ai on Oct 27, 2026. Anything I couldn't confirm on a live page is left out. To compare per-token, budget and request-quota plans with your own numbers, this &lt;a href="https://ankita37105.github.io/llm-api-cost-notes/calculator.html" rel="noopener noreferrer"&gt;LLM API cost calculator&lt;/a&gt; puts them side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Count your real requests before you pick
&lt;/h2&gt;

&lt;p&gt;A daily quota is only cheap if it covers your heavy days. Claude Code already keeps session transcripts as JSONL under &lt;code&gt;~/.claude/projects/&lt;/code&gt;, and each assistant turn there maps to one model request. This script counts them per day, deduping streamed chunks that share a message id:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# count_cc_requests.py: Claude Code model requests per day (UTC), from local transcripts
&lt;/span&gt;&lt;span class="kn"&gt;import&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;pathlib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;

&lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&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="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.claude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;projects&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;per_day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rglob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.jsonl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&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;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ignore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&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;JSONDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&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="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="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;msg_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&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="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="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;e&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uuid&lt;/span&gt;&lt;span class="sh"&gt;"&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;msg_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;10&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;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;per_day&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;per_day&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;per_day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;vals&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;per_day&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;median/day:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; busiest day:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with &lt;code&gt;python3 count_cc_requests.py&lt;/code&gt;. How I read the output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Busiest day under ~400:&lt;/strong&gt; the entry plan covers you, even on bad days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Median fine, busiest day 2–3x higher:&lt;/strong&gt; size for the busy day, or keep Max and use an API key only as overflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mostly Opus:&lt;/strong&gt; multiply your count before comparing, since Opus counts as more than one request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sub-agents and parallel sessions:&lt;/strong&gt; they show up in the same transcripts, so the count already includes them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Transcripts only go back as far as Claude Code keeps them, so run it again after a normal week if the history is short.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup: point Claude Code at the API in settings, not your shell
&lt;/h2&gt;

&lt;p&gt;Instead of exporting variables every session, put them in a project's &lt;code&gt;.claude/settings.json&lt;/code&gt; (or &lt;code&gt;~/.claude/settings.json&lt;/code&gt; for everything). Delete the block to go back to your Max login.&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;"env"&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;"ANTHROPIC_BASE_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://apiclaw.biz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_AUTH_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-apiclaw-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_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;"apiclaw/claude-sonnet-5.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;"ANTHROPIC_DEFAULT_SONNET_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;"apiclaw/claude-sonnet-5.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;"ANTHROPIC_DEFAULT_OPUS_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;"apiclaw/claude-opus-5.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;"ANTHROPIC_DEFAULT_HAIKU_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;"apiclaw/deepseek-v4-flash"&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;Fill every model slot, because Claude Code sends background and sub-agent work to the Haiku and Opus slots. Start &lt;code&gt;claude&lt;/code&gt;, run &lt;code&gt;/status&lt;/code&gt;, and confirm the base URL before a long task. Don't commit a project-level file with a real key; use &lt;code&gt;.claude/settings.local.json&lt;/code&gt; for that.&lt;/p&gt;

&lt;p&gt;The same key works in Cursor, Cline, Aider and the OpenAI SDK at &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;, with Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, Mistral, Llama and more behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Your script shows only a few dozen requests a day.&lt;/strong&gt; A per-token Console key, or Max's own usage credits, will cost less.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You run many agents in parallel all day.&lt;/strong&gt; That burns a daily quota fast; a concurrency-priced plan may suit you better if its model list works for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want the Max chat and Desktop features.&lt;/strong&gt; A gateway only replaces Claude Code's API calls, not the Claude apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need card billing right now.&lt;/strong&gt; Payment is crypto on site, with other methods via support (t.me/Apiclaw_support).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More gateways grouped by billing model are in this &lt;a href="https://github.com/ankita37105/openai-compatible-api-gateways" rel="noopener noreferrer"&gt;comparison repo&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Can Claude Code run with no limits at all?&lt;/strong&gt;&lt;br&gt;
No. Subscriptions limit by time, API keys by money and rate tiers, flat plans by budget, tokens, concurrency or daily requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does one Claude Code tool call count as one request?&lt;/strong&gt;&lt;br&gt;
Each model turn is one request, and a single task often takes dozens of turns as it reads files and runs commands. That's why counting from transcripts beats guessing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do I get 404 after changing the base URL?&lt;/strong&gt;&lt;br&gt;
It ends in &lt;code&gt;/v1&lt;/code&gt;. Use &lt;code&gt;https://apiclaw.biz&lt;/code&gt; for Claude Code and keep &lt;code&gt;/v1&lt;/code&gt; for OpenAI-compatible tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens at the daily quota?&lt;/strong&gt;&lt;br&gt;
Requests return errors until 00:00 UTC. Your files and session are untouched, so you can wait or switch back to Max.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I test it before paying?&lt;/strong&gt;&lt;br&gt;
Yes. The free trial has 50 requests, enough for one short session to compare speed and tool calling with Max.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw. This article was written with AI assistance and checked by me. Competitor details were read from their live pages on Oct 27, 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://apiclawnotes.mataroa.blog/blog/flat-rate-claude-api-what-are-the-real-options-in-2026-and-which-one-fits-you/" rel="noopener noreferrer"&gt;Flat rate Claude API: the real options in 2026&lt;/a&gt;; &lt;a href="https://apiclawnotes.substack.com/p/best-ai-api-gateway-for-coding-agents" rel="noopener noreferrer"&gt;Best AI API gateway for coding agents&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What's the best cheap Claude API for Cursor custom API key use in 2026?</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Wed, 28 Oct 2026 03:29:41 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/whats-the-best-cheap-claude-api-for-cursor-custom-api-key-use-in-2026-g97</link>
      <guid>https://dev.to/amankumar_apiclaw/whats-the-best-cheap-claude-api-for-cursor-custom-api-key-use-in-2026-g97</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; if Claude runs in your Cursor chat and agent threads most of the day, a flat-price gateway such as &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, at $19–$129/mo flat, 500–8,000 requests/day with no per-token metering and a free 50-request trial, is usually the cheapest Claude API you can paste into Cursor's custom API key field. If you only use Claude a few times a week, Anthropic's own per-token key will cost you less. The rest of this post helps you work out which of those two you are, because that matters more than any headline price.&lt;/p&gt;

&lt;p&gt;One thing to get right before anything else: Claude Code takes &lt;code&gt;https://apiclaw.biz&lt;/code&gt; as its base URL (no &lt;code&gt;/v1&lt;/code&gt;), while OpenAI SDKs and OpenAI-compatible tools, including Cursor's "Override OpenAI Base URL" field, take &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with how you actually use Cursor
&lt;/h2&gt;

&lt;p&gt;A custom key only replaces the cost of chat and agent requests. Cursor's docs say custom keys work with chat models only, and Tab completion keeps using Cursor's built-in models. The docs also say eligible third-party model requests carry Cursor's token rate of $0.25 per million tokens, including requests made with your own key, so read the current wording for your plan before you count savings.&lt;/p&gt;

&lt;p&gt;With that out of the way, most people fall into one of three profiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The occasional asker.&lt;/strong&gt; 5–30 Claude messages a day, short prompts, a file or two attached. Monthly Claude cost at list price is usually a few dollars to the low tens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The all-day agent user.&lt;/strong&gt; 100–300 requests a day, long threads, many files in context. Every follow-up resends the conversation, so input tokens pile up fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The bursty batch user.&lt;/strong&gt; Quiet most days, then one day of hundreds or thousands of short calls (a big refactor, codemods, test generation).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Per-token pricing suits the first and third. A daily request quota suits the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Options for a Claude key in Cursor (checked Oct 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Price model&lt;/th&gt;
&lt;th&gt;Claude Sonnet 5.5 cost&lt;/th&gt;
&lt;th&gt;Extra fees&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic API key&lt;/td&gt;
&lt;td&gt;Per token&lt;/td&gt;
&lt;td&gt;$2 input / $10 output per 1M tokens, cache reads $0.10&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Occasional asker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenRouter&lt;/td&gt;
&lt;td&gt;Prepaid credits, per token&lt;/td&gt;
&lt;td&gt;Provider price&lt;/td&gt;
&lt;td&gt;5.5% platform fee on Standard&lt;/td&gt;
&lt;td&gt;Occasional or bursty, many providers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requesty&lt;/td&gt;
&lt;td&gt;Pay as you go, per token&lt;/td&gt;
&lt;td&gt;Provider price&lt;/td&gt;
&lt;td&gt;5% markup&lt;/td&gt;
&lt;td&gt;Bursty, wants routing and spend tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CheapAI (cheapai.io)&lt;/td&gt;
&lt;td&gt;Discounted per token&lt;/td&gt;
&lt;td&gt;Lists Claude models below official price&lt;/td&gt;
&lt;td&gt;Billed in USD, RUB or crypto&lt;/td&gt;
&lt;td&gt;Per-token users chasing a lower rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw&lt;/td&gt;
&lt;td&gt;Flat monthly, daily request quota&lt;/td&gt;
&lt;td&gt;Same price per request at any prompt size&lt;/td&gt;
&lt;td&gt;None; heavier models like Opus count as more than one request&lt;/td&gt;
&lt;td&gt;All-day agent user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All five accept an API key in Cursor, but only Anthropic's own key goes into Cursor's Anthropic field. Gateways go into the OpenAI key field with the base URL override. If you want to compare these with your own numbers, plug them into this &lt;a href="https://ankita37105.github.io/llm-api-cost-notes/calculator.html" rel="noopener noreferrer"&gt;LLM API cost calculator&lt;/a&gt;, and a longer list of gateways and their limit types is in this &lt;a href="https://github.com/ankita37105/openai-compatible-api-gateways" rel="noopener noreferrer"&gt;OpenAI-compatible gateway comparison&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 2-minute test before you switch
&lt;/h2&gt;

&lt;p&gt;The cheapest way to choose is to measure one real request. Copy a typical Cursor prompt (say, a question plus one or two files you often attach) into &lt;code&gt;prompt.txt&lt;/code&gt;, then run this with Node 18+ and the official &lt;code&gt;openai&lt;/code&gt; package against any OpenAI-compatible endpoint you're considering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// measure.mjs: how many tokens does one of my Cursor-style requests use?&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompt.txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apiclaw/claude-sonnet-5.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prompt_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completion_tokens&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usage&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;perTokenCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;completion_tokens&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;e6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Sonnet 5.5 list price&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;prompt_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completion_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;perTokenCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;perTokenCost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Multiply by your requests per day x 22 work days for a monthly estimate.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;perTokenCost&lt;/code&gt; times your daily request count times 22 is clearly below $19, stay per-token. If it's well above the plan price and your busiest day fits under the daily quota, a flat plan saves money. The estimate ignores prompt caching, so treat it as an upper bound for per-token keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cursor settings that send requests somewhere else
&lt;/h2&gt;

&lt;p&gt;Most "my cheap key isn't being used" reports come down to one of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The model name starts with &lt;code&gt;claude-&lt;/code&gt;.&lt;/strong&gt; Cursor may match it to its own built-in Claude. Add a custom model with a prefixed ID such as &lt;code&gt;apiclaw/claude-sonnet-5.5&lt;/code&gt; or &lt;code&gt;apiclaw/claude-opus-5.5&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The base URL is missing &lt;code&gt;/v1&lt;/code&gt;.&lt;/strong&gt; Cursor's override is an OpenAI-compatible client, so it needs &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat works but agent mode errors.&lt;/strong&gt; Cursor's agent sends a slightly different request shape. Point the override at &lt;code&gt;https://apiclaw.biz/cursor&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The key went into the Anthropic field.&lt;/strong&gt; That field talks to Anthropic directly, so a gateway key is rejected there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After sending one message, check your provider's usage counter. If Cursor answered and the counter didn't move, Cursor served the request itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You're an occasional asker. Per-token billing will be cheaper, and the test above will show it.&lt;/li&gt;
&lt;li&gt;You mostly want faster or better Tab completion. No custom key affects Tab.&lt;/li&gt;
&lt;li&gt;You need card billing and invoices right now. APIClaw checkout is crypto on site, with other methods via support on Telegram.&lt;/li&gt;
&lt;li&gt;Your usage is bursty. A day with thousands of short calls can hit a daily quota where a per-token key would just keep going.&lt;/li&gt;
&lt;li&gt;You need Cursor's zero-data-retention guarantees. Cursor's docs say own-key requests fall outside that policy whichever provider you use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;APIClaw routes requests to models available through publicly available sources and provider APIs, and one key covers Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, Mistral, Llama and more, so you can switch a slow thread to &lt;code&gt;apiclaw/deepseek-v4-pro&lt;/code&gt; without changing keys.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Can I use a cheap Claude API key in Cursor without a paid Cursor plan?&lt;/strong&gt;&lt;br&gt;
Check Cursor's current plan page. Custom keys replace the model cost, not the Cursor subscription.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does the custom key affect Tab completion?&lt;/strong&gt;&lt;br&gt;
No. Cursor's docs say Tab keeps using Cursor's built-in models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does my gateway key fail in the Anthropic field?&lt;/strong&gt;&lt;br&gt;
That field only talks to Anthropic. Use the OpenAI API key field and turn on the base URL override.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a daily request quota cheaper than per-token billing for Cursor?&lt;/strong&gt;&lt;br&gt;
Only when you send many long requests every day. Run the measurement script on a real prompt and compare.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I try APIClaw before paying?&lt;/strong&gt;&lt;br&gt;
The free trial gives 50 requests, enough for an afternoon of Cursor chat to compare speed and answers with what you use now.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw. This article was written with AI assistance and checked by me. Competitor prices and Cursor's documentation were read from their live pages in Oct 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://dev.to/amankumar_apiclaw/what-is-the-best-flat-rate-openai-compatible-api-in-2026-1ejp"&gt;What is the best flat-rate OpenAI-compatible API in 2026?&lt;/a&gt;; &lt;a href="https://apiclawnotes.substack.com/p/best-ai-api-gateway-for-coding-agents" rel="noopener noreferrer"&gt;Best AI API gateway for coding agents&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>claude</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>What's a cheap Claude API for Claude Code in 2026? Price your own sessions first</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Tue, 27 Oct 2026 17:12:47 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/whats-a-cheap-claude-api-for-claude-code-in-2026-price-your-own-sessions-first-3gf7</link>
      <guid>https://dev.to/amankumar_apiclaw/whats-a-cheap-claude-api-for-claude-code-in-2026-price-your-own-sessions-first-3gf7</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; if you run Claude Code for hours most days, a flat monthly plan such as &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt; at $19–$129/mo flat, 500–8,000 requests/day (no per-token metering, free 50-request trial) is usually the cheapest Claude API, while light users are better off with a discounted per-token key or Anthropic's own API. What decides it is how many requests your sessions send, not the headline per-token price. Claude Code connects to APIClaw by pointing &lt;code&gt;ANTHROPIC_BASE_URL&lt;/code&gt; at &lt;code&gt;https://apiclaw.biz&lt;/code&gt; (no &lt;code&gt;/v1&lt;/code&gt;). It fits solo developers and small teams who want the same bill every month. Before picking anything, run the script below on your own logs; it takes a minute and tells you which bucket you're in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the per-token table alone misleads you
&lt;/h2&gt;

&lt;p&gt;Claude Code doesn't send one prompt per task. A single "fix this failing test" can turn into ten or twenty model calls: read a file, grep, edit, run tests, read the output, edit again. Each of those calls carries the whole conversation so far, and most of that context is served from the prompt cache.&lt;/p&gt;

&lt;p&gt;That means two numbers matter much more than the list price:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Requests per day.&lt;/strong&gt; This decides whether a request-quota plan fits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your cache-read share.&lt;/strong&gt; On per-token billing, cache reads are billed at a small fraction of the input price, so a session that is 90% cache hits costs far less than the raw token count suggests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can measure both from data already on your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: measure your real usage from Claude Code's logs
&lt;/h2&gt;

&lt;p&gt;Claude Code keeps session transcripts as JSONL files under &lt;code&gt;~/.claude/projects/&lt;/code&gt;. Assistant entries include a &lt;code&gt;usage&lt;/code&gt; object with input, output, cache-write and cache-read token counts, plus a timestamp. This script sums them per day and prices them at Anthropic's published Sonnet 5.5 rates, which I checked on claude.com/pricing this month:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Summarise Claude Code usage per day from local session logs.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="c1"&gt;# USD per 1M tokens, Anthropic Sonnet 5.5, checked Oct 2026 on claude.com/pricing.
# Add another provider's rates here if you want to compare.
&lt;/span&gt;&lt;span class="n"&gt;RATES&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;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;10.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_write&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_read&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.claude/projects/*/*.jsonl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;path&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;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ignore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;fh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&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;JSONDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msg&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entry&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="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="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requests&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;usage&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;usage&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_write&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;usage&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_creation_input_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_read&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;usage&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_read_input_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;RATES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;RATES&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;day&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;requests&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cache-read %&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;API cost $&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;all_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_write&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_read&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;share&lt;/span&gt; &lt;span class="o"&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;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_read&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;all_in&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;all_in&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;requests&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;13.0&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;%&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;12.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Average per active day: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&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;  (x 22 workdays = $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&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;/month)&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;A couple of caveats. Some entries can be logged more than once when a response streams in parts, so treat the request count as an upper bound. And the script prices everything at Sonnet rates; if you mostly run Opus, swap in those rates ($4 input, $20 output per million on the same page).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: read the result
&lt;/h2&gt;

&lt;p&gt;Look at two columns.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Average requests per day.&lt;/strong&gt; If it sits comfortably inside a plan's daily quota on your busiest days, a flat plan is predictable for you. If it spikes far above any quota a few times a month, per-token billing may handle those days better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monthly API cost.&lt;/strong&gt; If it comes out at a few dollars, stay on per-token billing; no flat plan will beat that. If it's well above the price of a flat plan that covers your request count, switching saves money.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you'd rather not do the arithmetic, I put the same comparison into a &lt;a href="https://ankita37105.github.io/llm-api-cost-notes/calculator.html" rel="noopener noreferrer"&gt;cost calculator&lt;/a&gt; where you enter requests per day and average tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  The options, checked Oct 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;How you pay&lt;/th&gt;
&lt;th&gt;Price checked Oct 2026&lt;/th&gt;
&lt;th&gt;What stops you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic API&lt;/td&gt;
&lt;td&gt;Per token&lt;/td&gt;
&lt;td&gt;Sonnet 5.5: $2 in / $10 out per 1M, cache read $0.10&lt;/td&gt;
&lt;td&gt;Spend and rate-limit tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Pro&lt;/td&gt;
&lt;td&gt;Subscription&lt;/td&gt;
&lt;td&gt;$20/mo monthly, $17/mo billed annually&lt;/td&gt;
&lt;td&gt;Usage limits on the plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Max&lt;/td&gt;
&lt;td&gt;Subscription&lt;/td&gt;
&lt;td&gt;From $100/mo (5x or 20x Pro usage)&lt;/td&gt;
&lt;td&gt;Usage limits on the plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokely&lt;/td&gt;
&lt;td&gt;Per token, prepaid&lt;/td&gt;
&lt;td&gt;Sonnet 5.5: $1.50 in / $7.50 out per 1M (25% off)&lt;/td&gt;
&lt;td&gt;Your balance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CheapAI&lt;/td&gt;
&lt;td&gt;Per token, prepaid&lt;/td&gt;
&lt;td&gt;Sonnet 5.5: $0.26 in / $1.33 out per 1M&lt;/td&gt;
&lt;td&gt;Your balance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard Compute&lt;/td&gt;
&lt;td&gt;Flat monthly&lt;/td&gt;
&lt;td&gt;From $19/mo, fixed compute budget&lt;/td&gt;
&lt;td&gt;Budget used up; no overage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw&lt;/td&gt;
&lt;td&gt;Flat monthly&lt;/td&gt;
&lt;td&gt;$19 to $129/mo, free 50-request trial&lt;/td&gt;
&lt;td&gt;Daily request quota&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sources: claude.com/pricing, tokely.me/claude-code-api, cheapai.io/en/claude-api, standardcompute.com/integrations/claude-code. I keep a longer side-by-side in &lt;a href="https://github.com/ankita37105/openai-compatible-api-gateways" rel="noopener noreferrer"&gt;this comparison repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: switch Claude Code with settings.json
&lt;/h2&gt;

&lt;p&gt;If you'd rather not export variables in every shell, Claude Code reads an &lt;code&gt;env&lt;/code&gt; block from &lt;code&gt;~/.claude/settings.json&lt;/code&gt;. For APIClaw it looks like this. Claude Code takes &lt;code&gt;https://apiclaw.biz&lt;/code&gt; as its base URL (no &lt;code&gt;/v1&lt;/code&gt;); OpenAI SDKs and OpenAI-compatible tools take &lt;code&gt;https://apiclaw.biz/v1&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="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"ANTHROPIC_BASE_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://apiclaw.biz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_AUTH_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-apiclaw-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_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;"apiclaw/claude-sonnet-5.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;"ANTHROPIC_DEFAULT_SONNET_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;"apiclaw/claude-sonnet-5.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;"ANTHROPIC_DEFAULT_OPUS_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;"apiclaw/claude-opus-5.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;"ANTHROPIC_DEFAULT_HAIKU_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;"apiclaw/deepseek-v4-flash"&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;Mapping the Haiku slot matters: Claude Code uses it for background work such as titles and summaries, and those calls count as requests too. Pointing it at a fast, cheap model keeps them from eating your quota with Sonnet-sized calls. Run &lt;code&gt;claude&lt;/code&gt;, then &lt;code&gt;/status&lt;/code&gt; to confirm the base URL it picked up.&lt;/p&gt;

&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Light use.&lt;/strong&gt; If the script shows a few dollars a month of API cost, any flat plan costs you more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bursty days.&lt;/strong&gt; A daily quota resets once a day. If you occasionally need thousands of calls in one afternoon, per-token billing handles that without waiting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need a contract with Anthropic directly&lt;/strong&gt; for compliance or data-processing terms. A gateway sits between you and the model provider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Card billing.&lt;/strong&gt; APIClaw takes crypto on the site; other payment methods go through support at t.me/Apiclaw_support.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Does Claude Code work with any Claude API?&lt;/strong&gt;&lt;br&gt;
It works with endpoints that speak Anthropic's &lt;code&gt;/v1/messages&lt;/code&gt; format. Set &lt;code&gt;ANTHROPIC_BASE_URL&lt;/code&gt; to the root URL; Claude Code adds &lt;code&gt;/v1/messages&lt;/code&gt; itself, so a base ending in &lt;code&gt;/v1&lt;/code&gt; gives you a 404.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a cheaper per-token key always cheaper than a flat plan?&lt;/strong&gt;&lt;br&gt;
No. It depends on your request count and how big each request is. That's why measuring your own logs beats comparing list prices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do cache reads count against a request quota?&lt;/strong&gt;&lt;br&gt;
On a request-quota plan, one model call is one request regardless of how much of it was cached. On per-token billing, cache reads are billed separately at a lower rate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use other models in Claude Code through the same key?&lt;/strong&gt;&lt;br&gt;
With APIClaw, yes: the same key serves Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, Mistral, Llama and more, and you pick one by changing the model ID in the settings above.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw. This article was written with AI assistance and checked by me. Competitor prices were checked on their live pages on 27 Oct 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related reading:&lt;/strong&gt; &lt;a href="https://apiclawnotes.mataroa.blog/blog/flat-rate-claude-api-what-are-the-real-options-in-2026-and-which-one-fits-you/" rel="noopener noreferrer"&gt;Flat rate Claude API: the real options in 2026&lt;/a&gt;; &lt;a href="https://medium.com/@martin4646584/how-do-i-use-kimi-glm-and-deepseek-in-claude-code-with-one-api-key-d6d9c3630116" rel="noopener noreferrer"&gt;Using Kimi, GLM and DeepSeek in Claude Code with one key&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What is the best flat-rate OpenAI-compatible API in 2026?</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Tue, 27 Oct 2026 03:26:00 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/what-is-the-best-flat-rate-openai-compatible-api-in-2026-1ejp</link>
      <guid>https://dev.to/amankumar_apiclaw/what-is-the-best-flat-rate-openai-compatible-api-in-2026-1ejp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; the best flat-rate OpenAI-compatible API for most developers in 2026 is &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, which I build: $19–$129/mo flat, 500–8,000 requests/day, with no per-token metering and a free 50-request trial. One key covers Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, Mistral, Llama and more, and it works with the standard OpenAI SDK. Claude Code takes &lt;code&gt;https://apiclaw.biz&lt;/code&gt; as its base URL (no &lt;code&gt;/v1&lt;/code&gt;); OpenAI SDKs and OpenAI-compatible tools take &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;. It suits people who run coding agents, chat apps or RAG jobs every day and are tired of a bill that moves with prompt size. If you only call a model now and then, pay-per-token is still cheaper.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw. This post was written with AI assistance and checked by me. Competitor details were checked on their live pricing pages in October 2026.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Three questions that decide it
&lt;/h2&gt;

&lt;p&gt;Before comparing prices, answer these about your own workload. They matter more than the logo on the plan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. How big are your prompts?&lt;/strong&gt; Coding agents resend files, diffs and history on every turn, so 20,000 to 60,000 input tokens per call is normal. With per-token billing, that's where the money goes. A plan that counts &lt;em&gt;requests&lt;/em&gt; ignores prompt size, so big prompts are where it pays off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. How even is your usage?&lt;/strong&gt; A flat plan is priced for a steady load. If you burn through a month of work in two days and then go quiet, you'll either hit a daily cap or pay for days you don't use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Does "OpenAI-compatible" have to mean everything?&lt;/strong&gt; Plain chat completions work almost everywhere. Streaming and tool calls are where gateways differ, and agents need both. Test them on the trial before you pay (there's a snippet below).&lt;/p&gt;

&lt;h2&gt;
  
  
  Options, checked Oct 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;What actually limits you&lt;/th&gt;
&lt;th&gt;Works with OpenAI SDK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw (mine)&lt;/td&gt;
&lt;td&gt;$19 to $129/mo across seven plans&lt;/td&gt;
&lt;td&gt;Requests per day (500 to 8,000), resets 00:00 UTC; heavier models count as more than one request&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard Compute&lt;/td&gt;
&lt;td&gt;$19, $39, $89, $249/mo individual plans&lt;/td&gt;
&lt;td&gt;A monthly compute budget ($20, $41, $95, $269); requests stop when it runs out, top-ups at usage + 5%&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenRouter&lt;/td&gt;
&lt;td&gt;Pay as you go&lt;/td&gt;
&lt;td&gt;Tokens at provider list price, plus a 5.5% fee on credit purchases (Standard plan); not flat-rate&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-hosted proxy (e.g. LiteLLM)&lt;/td&gt;
&lt;td&gt;Free software&lt;/td&gt;
&lt;td&gt;Whatever each provider bills you per token&lt;/td&gt;
&lt;td&gt;Yes, but you run it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The real split is &lt;strong&gt;request quota vs. compute budget&lt;/strong&gt;. A compute budget is still per-token underneath: a $41 budget goes a long way on short prompts and fast on 50k-token agent turns. A request quota is the opposite: it doesn't care about prompt length, but very high volumes of tiny calls will hit the daily ceiling.&lt;/p&gt;

&lt;p&gt;To put your own numbers in, this &lt;a href="https://ankita37105.github.io/llm-api-cost-notes/calculator.html" rel="noopener noreferrer"&gt;LLM API cost calculator&lt;/a&gt; compares per-token pricing, OpenRouter, Claude subscriptions and request-quota plans for a given requests-per-day and token size. There's also a longer &lt;a href="https://github.com/ankita37105/openai-compatible-api-gateways" rel="noopener noreferrer"&gt;list of OpenAI-compatible gateways&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup: one base URL, and a guard for the daily quota
&lt;/h2&gt;

&lt;p&gt;Any OpenAI-format client needs two values. Here's the official Node SDK with a small wrapper that counts requests per UTC day, so a batch job slows down and warns you before it hits the quota instead of failing halfway through.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// quota-client.ts â€” npm i openai&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OpenAI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DAILY_QUOTA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DAILY_QUOTA&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// your plan's requests/day&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WARN_AT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// UTC date, matches the reset&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;today&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;today&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;DAILY_QUOTA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Daily quota of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DAILY_QUOTA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; reached; resumes after 00:00 UTC`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;DAILY_QUOTA&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;WARN_AT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`[quota] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;used&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;DAILY_QUOTA&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; requests used today`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;used&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Same key, different model families: only the model string changes.&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apiclaw/claude-sonnet-5.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Summarise what a request quota is in one line.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apiclaw/deepseek-v4-flash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Same question, one line.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The counter is local and approximate (it doesn't know that a heavier model like Claude Opus may count as more than one request), so treat it as an early warning and keep the dashboard as the source of truth.&lt;/p&gt;

&lt;p&gt;For tools rather than code, the same two values go into the "OpenAI base URL" and "API key" fields of Cursor, Cline, Continue, Aider and similar editors. Claude Code is the one exception: it speaks Anthropic's format, so it takes &lt;code&gt;ANTHROPIC_BASE_URL=https://apiclaw.biz&lt;/code&gt; with no &lt;code&gt;/v1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick compatibility check
&lt;/h2&gt;

&lt;p&gt;Before paying for any flat plan, run one streaming call and one tool call against it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://apiclaw.biz/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;$APICLAW_API_KEY&lt;/span&gt;&lt;span class="s2"&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":"apiclaw/claude-sonnet-5.5","stream":true,
       "messages":[{"role":"user","content":"Count to 3."}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;data:&lt;/code&gt; chunks ending in &lt;code&gt;data: [DONE]&lt;/code&gt;, streaming is fine. Repeat with a &lt;code&gt;tools&lt;/code&gt; array and check that &lt;code&gt;tool_calls&lt;/code&gt; comes back as valid JSON. Do the same on every provider you're comparing; it takes two minutes and saves a month of regret.&lt;/p&gt;

&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Light, occasional use.&lt;/strong&gt; A few hundred calls a month costs very little per-token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Huge numbers of tiny calls.&lt;/strong&gt; Tens of thousands of short classifications a day fit a token budget or direct vendor pricing better than a request quota.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need an SLA, a signed contract or invoicing from a specific entity.&lt;/strong&gt; Go to the model vendor or an enterprise gateway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You can't pay with crypto.&lt;/strong&gt; Checkout on the site is crypto; other payment methods go through support on Telegram.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Is any flat-rate OpenAI-compatible API truly uncapped?&lt;/strong&gt;&lt;br&gt;
No. Each caps something: requests per day, a dollar budget, a fair-use ceiling or a time window. Compare the cap, not the sticker price.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do long prompts cost more on a request quota?&lt;/strong&gt;&lt;br&gt;
Not on APIClaw. A 40,000-token request counts the same as a 400-token one, though heavier models count as more than one request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I switch between Claude and GPT without changing keys?&lt;/strong&gt;&lt;br&gt;
Yes. Change the model string, for example from &lt;code&gt;apiclaw/claude-sonnet-5.5&lt;/code&gt; to &lt;code&gt;apiclaw/gpt-6-sol&lt;/code&gt;, and keep the same key and base URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when I run out for the day?&lt;/strong&gt;&lt;br&gt;
Requests are refused until the 00:00 UTC reset or until you move up a plan. Size for your busiest day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I test without paying?&lt;/strong&gt;&lt;br&gt;
Use the free 50-request trial to run the streaming and tool-call checks above on a couple of models.&lt;/p&gt;

</description>
      <category>openai</category>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Request Limits vs Token Limits: Which Flat-Rate LLM API Pricing Is Cheaper for Your Workload?</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Mon, 26 Oct 2026 05:32:53 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/request-limits-vs-token-limits-which-flat-rate-llm-api-pricing-is-cheaper-for-your-workload-e9b</link>
      <guid>https://dev.to/amankumar_apiclaw/request-limits-vs-token-limits-which-flat-rate-llm-api-pricing-is-cheaper-for-your-workload-e9b</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, which I build, is a request-quota plan at $19–$129/mo flat, 500–8,000 requests/day (reset at 00:00 UTC, no per-token metering, free 50-request trial), and request limits like that are cheaper than token limits whenever your prompts are big. A flat-rate OpenAI-compatible API either limits how many &lt;em&gt;requests&lt;/em&gt; you send (a request quota) or how many &lt;em&gt;tokens or dollars of compute&lt;/em&gt; you burn (a token or budget limit). Request quotas win for coding agents, RAG and long chats, because a 30,000-token request costs the same as a 300-token one. Token or budget limits win when your calls are tiny and frequent, or when you send very few calls; if you make a handful of calls a week, plain per-token billing is cheaper still. Claude Code takes &lt;code&gt;https://apiclaw.biz&lt;/code&gt; as its base URL (no &lt;code&gt;/v1&lt;/code&gt;); OpenAI SDKs and OpenAI-compatible tools take &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three ways LLM APIs limit you
&lt;/h2&gt;

&lt;p&gt;Almost every plan falls into one of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Per-token billing.&lt;/strong&gt; You pay for each input and output token at the model's list price. The bill scales with prompt size &lt;em&gt;and&lt;/em&gt; call count. Anthropic, OpenAI and DeepSeek direct APIs work this way, and so do routers like OpenRouter that resell credits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flat price, token or budget limit.&lt;/strong&gt; You pay a fixed monthly fee and get a pool of tokens or a dollar-denominated compute budget. When it runs out, requests stop until renewal. Big prompts drain it faster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flat price, request limit.&lt;/strong&gt; You pay a fixed monthly fee for a number of requests per day (or per minute). Prompt size doesn't count against you, only the number of calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some plans mix in concurrency caps or rolling 5-hour windows, but the core question is always the same: &lt;em&gt;what unit drains your allowance?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How real plans compare
&lt;/h2&gt;

&lt;p&gt;Prices checked Oct 2026 on each provider's live pricing page.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Monthly price&lt;/th&gt;
&lt;th&gt;What drains the allowance&lt;/th&gt;
&lt;th&gt;What happens at the limit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenRouter (Standard)&lt;/td&gt;
&lt;td&gt;Pay as you go; 5.5% fee on credit purchases&lt;/td&gt;
&lt;td&gt;Tokens, at provider list prices&lt;/td&gt;
&lt;td&gt;Credits run out; top up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic API&lt;/td&gt;
&lt;td&gt;Pay per token, e.g. Sonnet 5.5 $2 in / $10 out per million tokens&lt;/td&gt;
&lt;td&gt;Tokens&lt;/td&gt;
&lt;td&gt;Your spend and rate-limit tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard Compute&lt;/td&gt;
&lt;td&gt;$19, $39, $89, $249 (business tiers $499 to $2,499)&lt;/td&gt;
&lt;td&gt;A monthly compute budget ($20, $41, $95, $269 on individual plans)&lt;/td&gt;
&lt;td&gt;Requests stop until renewal or upgrade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Electron Hub DevPass&lt;/td&gt;
&lt;td&gt;Lite $10, Turbo $40&lt;/td&gt;
&lt;td&gt;Requests per minute and concurrency slots (8 or 20 RPM, 2 or 5 slots)&lt;/td&gt;
&lt;td&gt;Throttled; curated open coding models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw&lt;/td&gt;
&lt;td&gt;$19, $39, $59, $69, $89, $99, $129&lt;/td&gt;
&lt;td&gt;Requests per day (500, 1,000, 1,500, 3,000, 4,000, 6,000, 8,000)&lt;/td&gt;
&lt;td&gt;Wait for the 00:00 UTC reset or move up a plan&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A side-by-side list of more gateways, kept up to date, is in this &lt;a href="https://github.com/ankita37105/openai-compatible-api-gateways" rel="noopener noreferrer"&gt;comparison of OpenAI-compatible gateways&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: same calls, very different bills
&lt;/h2&gt;

&lt;p&gt;Take Sonnet-class pricing of $2 per million input tokens and $10 per million output tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workload A, a coding agent.&lt;/strong&gt; Each call sends about 20,000 input tokens (files, history, tool output) and gets 1,000 back. That's $0.04 + $0.01 = &lt;strong&gt;$0.05 per call&lt;/strong&gt;. At 500 calls a day for 30 days, 15,000 calls cost about &lt;strong&gt;$750 a month&lt;/strong&gt; per token. On a 500-requests-a-day quota, it's $19. A compute-budget plan would need a budget in the hundreds of dollars for the same work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workload B, a tiny classifier.&lt;/strong&gt; Each call sends 500 input tokens and gets 200 back: $0.001 + $0.002 = &lt;strong&gt;$0.003 per call&lt;/strong&gt;. At 300 calls a &lt;em&gt;month&lt;/em&gt;, that's about &lt;strong&gt;$0.90&lt;/strong&gt;. Any flat plan is a waste of money here; pay per token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workload C, high-volume short calls.&lt;/strong&gt; 20,000 calls a day at 400 tokens each. Per token that's roughly $0.002 per call, or about $1,200 a month, and it blows past any daily request quota I know of. This is where a token-budget plan or direct per-token pricing with volume discounts fits better.&lt;/p&gt;

&lt;p&gt;The rule of thumb: &lt;strong&gt;divide average tokens per call by calls per day.&lt;/strong&gt; Big prompts and moderate call counts favour request quotas. Small prompts and huge call counts favour token pricing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Price your own workload from logs
&lt;/h2&gt;

&lt;p&gt;If you already log usage (the OpenAI SDK returns &lt;code&gt;usage.prompt_tokens&lt;/code&gt; and &lt;code&gt;usage.completion_tokens&lt;/code&gt; on every response), this script turns a JSONL log into a monthly cost under each model:&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;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;defaultdict&lt;/span&gt;

&lt;span class="c1"&gt;# Per-million-token prices for the per-token comparison (edit to match your model).
&lt;/span&gt;&lt;span class="n"&gt;PRICE_IN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.00&lt;/span&gt;
&lt;span class="n"&gt;PRICE_OUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;10.00&lt;/span&gt;

&lt;span class="c1"&gt;# Request-quota tiers: (monthly price, requests per day)
&lt;/span&gt;&lt;span class="n"&gt;QUOTA_TIERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;69&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;129&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8000&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;load&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="n"&gt;per_day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defaultdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&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;calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;with&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="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# {"date": "2026-10-25", "prompt_tokens": 1234, "completion_tokens": 321}
&lt;/span&gt;            &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;per_day&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;row&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_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;d&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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;completion_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&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;per_day&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;estimate&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="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load&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="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tok_in&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;tok_out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;peak_calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;per_token_month&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tok_in&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;PRICE_IN&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tok_out&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;PRICE_OUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;QUOTA_TIERS&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;peak_calls&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;days logged: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, peak calls/day: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;peak_calls&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;avg tokens per call: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;tok_in&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tok_out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;calls&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;per-token estimate: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;per_token_month&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&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;/month&lt;/span&gt;&lt;span class="sh"&gt;"&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;tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;smallest request-quota tier covering your peak day: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tier&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/month (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/day)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your peak day exceeds 8,000 requests; a request quota won&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t cover it&lt;/span&gt;&lt;span class="sh"&gt;"&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;estimate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;usage.jsonl&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;Size the quota to your &lt;strong&gt;peak&lt;/strong&gt; day, not your average, because a daily request quota stops you on the day you exceed it. Token budgets have the opposite failure mode: a single heavy week can drain the whole month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching is two environment variables
&lt;/h2&gt;

&lt;p&gt;Every plan in the table above speaks the OpenAI Chat Completions format, so trying a different pricing model doesn't mean rewriting code:&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;base_url&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_BASE_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;https://apiclaw.biz/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="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;OPENAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apiclaw/claude-sonnet-5.5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarise this diff in two sentences.&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;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# keep logging this so you can re-run the estimate later
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a request quota, one habit pays off: &lt;strong&gt;batch small asks into one call&lt;/strong&gt; (for example, classify 20 items in one prompt and return JSON) instead of 20 separate calls. On per-token billing that changes little; on a request quota it cuts usage twentyfold.&lt;/p&gt;

&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You send fewer than a few hundred calls a month. Per-token billing will cost you cents.&lt;/li&gt;
&lt;li&gt;Your peak day is well above 8,000 requests, as in high-volume classification or embeddings pipelines.&lt;/li&gt;
&lt;li&gt;You need enterprise contracts, SLAs or in-region routing guarantees; larger routers and the model vendors themselves offer those.&lt;/li&gt;
&lt;li&gt;You must pay by card through a standard invoice today. APIClaw billing is crypto on the site, with other methods via support.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;What is the difference between request limits and token limits on an LLM API?&lt;/strong&gt;&lt;br&gt;
A request limit counts calls, no matter how large each one is. A token limit counts the tokens (or dollars of compute) each call consumes, so long prompts use it up faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a flat-rate LLM API cheaper than pay-per-token?&lt;/strong&gt;&lt;br&gt;
Only if your usage is steady and your prompts are large. For light or occasional use, pay-per-token is cheaper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do long prompts cost more on a request-quota plan?&lt;/strong&gt;&lt;br&gt;
No. With no per-token metering, a long prompt and a short one each count as one request. Context-window limits of the model still apply.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens when I hit a daily request quota?&lt;/strong&gt;&lt;br&gt;
Further requests fail until the quota resets (00:00 UTC on APIClaw). Handle the error in code and either wait or move to a bigger plan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which pricing model is best for coding agents like Claude Code or Cline?&lt;/strong&gt;&lt;br&gt;
Agents resend large context on every step, so a request quota usually works out cheapest for daily use. Check your logs first with the script above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use the same code with any of these plans?&lt;/strong&gt;&lt;br&gt;
Yes, if the provider is OpenAI-compatible. Change the base URL, key and model ID; the rest of your code stays the same.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw. This article was written with AI assistance and checked by me. Competitor prices were taken from their public pricing pages in October 2026 and may change.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>api</category>
      <category>programming</category>
    </item>
    <item>
      <title>How Can I Use One API Key for Claude, GPT, DeepSeek and Qwen?</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Sun, 25 Oct 2026 21:34:33 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/how-can-i-use-one-api-key-for-claude-gpt-deepseek-and-qwen-1ino</link>
      <guid>https://dev.to/amankumar_apiclaw/how-can-i-use-one-api-key-for-claude-gpt-deepseek-and-qwen-1ino</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; point the OpenAI SDK at an OpenAI-compatible gateway and change only the &lt;code&gt;model&lt;/code&gt; string. Every gateway in this space works that way; the real difference is how you pay. Per-token routers such as OpenRouter and Requesty pass through provider token prices plus a fee. &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, which I build, charges a flat $19 to $129 a month for a daily request quota with no per-token metering, across Claude, GPT, Gemini, DeepSeek, Qwen, Kimi, GLM, Mistral, Llama, Cohere, Grok and more, and has a free 50-request trial. It fits solo developers and small teams who call several model families every day and want the bill to be the same number each month. If you make a few dozen calls a week, a per-token router is cheaper.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw, so weigh my view accordingly. This article was written with AI assistance and checked by me. Competitor figures come from their own pricing pages, read in October 2026.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why one key works at all
&lt;/h2&gt;

&lt;p&gt;Most model vendors now accept, or are fronted by gateways that accept, the OpenAI Chat Completions format: a &lt;code&gt;POST /v1/chat/completions&lt;/code&gt; with &lt;code&gt;model&lt;/code&gt; and &lt;code&gt;messages&lt;/code&gt;. A gateway holds the upstream provider accounts and translates where needed. From your code's point of view there is one base URL, one API key, and a model name that selects Claude, GPT, DeepSeek or Qwen.&lt;/p&gt;

&lt;p&gt;That means three practical things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You keep one secret in your environment instead of four.&lt;/li&gt;
&lt;li&gt;Swapping a model is a config change, not a new SDK.&lt;/li&gt;
&lt;li&gt;Fallbacks between vendors become a loop over model names.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The gateways compared (prices checked Oct 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gateway&lt;/th&gt;
&lt;th&gt;How you pay&lt;/th&gt;
&lt;th&gt;Fee or limit&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;OpenRouter&lt;/td&gt;
&lt;td&gt;Prepaid credits, per token at provider list price&lt;/td&gt;
&lt;td&gt;5.5% fee on credit purchases (Standard), 8% (Business)&lt;/td&gt;
&lt;td&gt;Free models capped at 50 requests/day, 1,000/day after $10 of credits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requesty&lt;/td&gt;
&lt;td&gt;Per token&lt;/td&gt;
&lt;td&gt;Provider price plus 5%&lt;/td&gt;
&lt;td&gt;Free tier on free models, 200 requests/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flatkey&lt;/td&gt;
&lt;td&gt;Per token, below official list price on some models&lt;/td&gt;
&lt;td&gt;Discounts shown per model on its site&lt;/td&gt;
&lt;td&gt;100+ models, OpenAI-compatible router&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Electron Hub&lt;/td&gt;
&lt;td&gt;Monthly plan that buys weekly credits&lt;/td&gt;
&lt;td&gt;$10 to $249/month; $8 to $200 weekly credits; 10 to 100 requests/minute&lt;/td&gt;
&lt;td&gt;Credits refill Sundays 21:00 UTC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw&lt;/td&gt;
&lt;td&gt;Flat monthly&lt;/td&gt;
&lt;td&gt;$19 to $129/month for 500 to 8,000 requests/day; no per-token metering&lt;/td&gt;
&lt;td&gt;Free 50-request trial; crypto on site, other methods via support&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I only listed numbers I could read on each vendor's page this month. I haven't benchmarked latency, so this is a pricing map rather than a review. A longer side-by-side lives in this &lt;a href="https://github.com/ankita37105/openai-compatible-api-gateways" rel="noopener noreferrer"&gt;comparison of OpenAI-compatible API gateways&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code: one client, four model families
&lt;/h2&gt;

&lt;p&gt;Install the official SDK (&lt;code&gt;pip install openai&lt;/code&gt;) and set two environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://apiclaw.biz/v1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sk-your-apiclaw-key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK reads both automatically, so the client needs no arguments:&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="c1"&gt;# picks up OPENAI_BASE_URL and OPENAI_API_KEY
&lt;/span&gt;
&lt;span class="n"&gt;MODELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude&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;apiclaw/claude-sonnet-5.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;gpt&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;apiclaw/gpt-6-sol&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deepseek&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;apiclaw/deepseek-v4-pro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen&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;apiclaw/qwen3.8-max-0902&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&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;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;family&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;MODELS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain a Python context manager in two sentences.&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;Nothing in that loop knows which vendor it's talking to. The same pattern works in Node:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apiclaw/deepseek-v4-pro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write a regex for ISO dates.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pick the model per task, not per project
&lt;/h2&gt;

&lt;p&gt;Once switching is free, routing by task is the useful step. A small table in config is enough:&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;ROUTES&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;code_review&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;apiclaw/claude-sonnet-5.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;bulk_summaries&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;apiclaw/deepseek-v4-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;multilingual&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;apiclaw/qwen3.8-max-0902&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;general&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;apiclaw/gpt-6-sol&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ROUTES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ROUTES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;general&lt;/span&gt;&lt;span class="sh"&gt;"&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under per-token pricing, you route cheap jobs to cheap models to save money. Under a request quota every call costs the same one request, so you can route purely on quality and keep the cheap models for latency-sensitive work.&lt;/p&gt;

&lt;h2&gt;
  
  
  A cross-vendor fallback in ten lines
&lt;/h2&gt;

&lt;p&gt;Different vendors fail at different times, which is the main reliability win of one key:&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;APIError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RateLimitError&lt;/span&gt;

&lt;span class="n"&gt;FALLBACK&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;apiclaw/claude-sonnet-5.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;apiclaw/gpt-6-sol&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;apiclaw/deepseek-v4-pro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask_with_fallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;last_err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;FALLBACK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
                &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;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="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RateLimitError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;APIError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;last_err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;last_err&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the list short. Three families from different vendors covers nearly every outage without hiding real bugs behind endless retries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that still differ between models
&lt;/h2&gt;

&lt;p&gt;One key normalises the request format, not the models. Watch for these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context windows and output limits&lt;/strong&gt; vary by model. Set &lt;code&gt;max_tokens&lt;/code&gt; explicitly instead of relying on defaults.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool calling&lt;/strong&gt; works through the same &lt;code&gt;tools&lt;/code&gt; parameter, but smaller models follow complex schemas less reliably. Test each model you route tool calls to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System prompt sensitivity&lt;/strong&gt; differs. A prompt tuned for Claude may need a line or two of changes for Qwen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning models&lt;/strong&gt; may return extra reasoning content or take longer. Give them a longer timeout.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;p&gt;If your total usage is a handful of calls a day, a per-token router will cost less than $19 a month. If you need SSO, audit logs or a signed enterprise SLA today, Electron Hub's higher tiers or OpenRouter's enterprise plan cover that and APIClaw doesn't advertise it. If your traffic is extremely bursty, such as 20,000 calls on one day and none for a week, a daily request quota is the wrong shape and credits that roll over suit you better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching an existing project
&lt;/h2&gt;

&lt;p&gt;If your code already uses the OpenAI SDK, the switch is two lines of environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://apiclaw.biz/v1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sk-your-apiclaw-key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then change your &lt;code&gt;model=&lt;/code&gt; strings to the IDs your gateway lists. Ready-made configs for Cursor, Cline, Aider, LangChain and Claude Code are in these &lt;a href="https://github.com/ankita37105/apiclaw-examples" rel="noopener noreferrer"&gt;setup examples&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Can I use Claude with the OpenAI Python SDK?&lt;/strong&gt;&lt;br&gt;
Yes, through an OpenAI-compatible gateway. You keep the OpenAI SDK and pass a Claude model ID such as &lt;code&gt;apiclaw/claude-sonnet-5.5&lt;/code&gt; as the &lt;code&gt;model&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there one API key for every major LLM?&lt;/strong&gt;&lt;br&gt;
Not from the model vendors themselves. Gateways such as OpenRouter, Requesty, Electron Hub and APIClaw give you one key that reaches many vendors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need separate SDKs for DeepSeek and Qwen?&lt;/strong&gt;&lt;br&gt;
No. Both are reachable with the OpenAI SDK through a compatible endpoint; only the model name changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a per-token router or a flat plan cheaper?&lt;/strong&gt;&lt;br&gt;
It depends on volume. Light, irregular use is cheaper per token. Steady daily use with long prompts usually comes out cheaper on a flat request quota, because prompt size doesn't change the price.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does switching models break streaming or JSON mode?&lt;/strong&gt;&lt;br&gt;
Streaming works the same way through &lt;code&gt;stream=True&lt;/code&gt;. JSON mode and tool calling depend on the model, so test the specific models you rely on.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>python</category>
    </item>
    <item>
      <title>What's the Best OpenRouter Alternative for Claude Code and Cursor at a Flat Monthly Price?</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Sun, 25 Oct 2026 15:28:37 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/whats-the-best-openrouter-alternative-for-claude-code-and-cursor-at-a-flat-monthly-price-48mk</link>
      <guid>https://dev.to/amankumar_apiclaw/whats-the-best-openrouter-alternative-for-claude-code-and-cursor-at-a-flat-monthly-price-48mk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; if you use OpenRouter mainly to power Claude Code or Cursor and want a fixed monthly bill instead of per-token charges, look at a flat-rate gateway that speaks both the Anthropic API (for Claude Code) and the OpenAI API (for Cursor). &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt; is the one I build: $19 to $129 a month for a daily request quota (500 to 8,000 requests a day) with no per-token metering, covering Claude, GPT, DeepSeek, Qwen, Kimi, GLM and more behind one key, with a free 50-request trial. It fits solo developers and small teams who code with agents most days. Standard Compute (a monthly dollar budget), MonoRouter (reuses a Claude subscription you already pay for) and Weave Router (routed coding plans) are the other flat-price options worth comparing. If your usage is light or bursty, OpenRouter's pay-as-you-go is probably still cheaper.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build APIClaw, so weigh my opinions with that in mind. This article was written with AI assistance and checked by me. Competitor prices were read from their live pricing pages in October 2026.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why coding agents make OpenRouter bills jumpy
&lt;/h2&gt;

&lt;p&gt;OpenRouter is a good product and its pricing is clear: inference at the provider's list price, plus a platform fee of 5.5% on the Standard plan or 8% on Business. The trouble is the workload, not the fee.&lt;/p&gt;

&lt;p&gt;Claude Code and Cursor's agent mode don't send one prompt per task. Every tool step (read a file, run a test, edit, re-run) is a new request that carries the whole growing conversation. A refactor that takes 30 steps re-sends your context 30 times, and with per-token billing you pay for all of it. Two developers doing "the same amount of work" can end the month with very different bills, depending on how long their sessions run and which model they leave selected.&lt;/p&gt;

&lt;p&gt;A flat-price plan swaps that uncertainty for a different limit. The question is which limit suits you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flat-price options compared (prices checked Oct 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;What the limit is&lt;/th&gt;
&lt;th&gt;Works with Claude Code&lt;/th&gt;
&lt;th&gt;Works with Cursor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenRouter (baseline)&lt;/td&gt;
&lt;td&gt;Pay as you go, plus 5.5% fee (Standard) or 8% (Business)&lt;/td&gt;
&lt;td&gt;Your credit balance; optional budget controls on paid plans&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;APIClaw&lt;/td&gt;
&lt;td&gt;$19 (500 req/day), $39 (1,000), $59 (1,500), $69 (3,000), $89 (4,000), $99 (6,000), $129 (8,000)&lt;/td&gt;
&lt;td&gt;Daily request quota, resets 00:00 UTC; no per-token metering&lt;/td&gt;
&lt;td&gt;Yes, Anthropic-compatible base URL&lt;/td&gt;
&lt;td&gt;Yes, OpenAI base URL override plus a Cursor agent endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standard Compute&lt;/td&gt;
&lt;td&gt;$19, $39, $89, $249 and up&lt;/td&gt;
&lt;td&gt;A monthly compute budget in dollars ($20, $41, $95, $269 on those plans); requests stop at the budget until renewal&lt;/td&gt;
&lt;td&gt;Check their docs&lt;/td&gt;
&lt;td&gt;Check their docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MonoRouter&lt;/td&gt;
&lt;td&gt;Free (1,500 calls lifetime), $9 (10,000 calls/mo), $29 (unlimited calls), $99 team (5 seats)&lt;/td&gt;
&lt;td&gt;Routes calls through a Claude subscription you already pay for, so that plan's own limits still apply&lt;/td&gt;
&lt;td&gt;Yes, Anthropic SDK-style&lt;/td&gt;
&lt;td&gt;Not stated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weave Router&lt;/td&gt;
&lt;td&gt;$10/mo Code Max (open-source models only), $100/mo Code Boost (OpenAI, Anthropic and open models)&lt;/td&gt;
&lt;td&gt;Routed coding subscription; Code Boost is pitched as stretching existing Claude and Codex subscriptions&lt;/td&gt;
&lt;td&gt;Check their docs&lt;/td&gt;
&lt;td&gt;Check their docs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I've only listed what each pricing page states. Where a page didn't say how a tool connects, I wrote "check their docs" rather than guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose between them
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You want the most predictable month and use Claude Code or Cursor daily:&lt;/strong&gt; a request quota is the easiest limit to reason about, because a long context costs the same as a short one. That's the APIClaw model. Size the plan by requests, not tokens: count how many agent steps a typical day takes, then add headroom.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You prefer a dollar budget with model routing:&lt;/strong&gt; Standard Compute caps you at a monthly budget and routes each request to a model and provider. Your spend is fixed, but how much work the budget covers still depends on tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You already pay for Claude Max and want to share it or use it from your own apps:&lt;/strong&gt; MonoRouter is built for that. Your cost is the MonoRouter plan plus the Claude subscription, and the subscription's usage windows still apply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want cheap open-source coding models and don't need Claude:&lt;/strong&gt; Weave Router's $10 plan is the lowest sticker price here.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When APIClaw isn't the right choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Very light use.&lt;/strong&gt; If you send a few dozen requests a week, pay-as-you-go on OpenRouter will cost less than any monthly plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need card billing or an invoice today.&lt;/strong&gt; APIClaw billing is crypto on the site; other payment methods go through support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need Cursor's Tab completion or Composer on your key.&lt;/strong&gt; That isn't a gateway limit. Cursor keeps Tab on its own models whatever you configure, and Composer models refuse custom keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise procurement.&lt;/strong&gt; If you need a signed DPA, SSO and contractual SLAs out of the box, OpenRouter's Enterprise tier or a self-hosted gateway is a better fit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Switching Claude Code and Cursor (the short version)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; reads its settings from &lt;code&gt;~/.claude/settings.json&lt;/code&gt; (Windows: &lt;code&gt;%USERPROFILE%\.claude\settings.json&lt;/code&gt;). Point it at the gateway's Anthropic-compatible root. Note there's no &lt;code&gt;/v1&lt;/code&gt; here, because Claude Code adds the Anthropic paths itself:&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;"env"&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;"ANTHROPIC_BASE_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://apiclaw.biz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_AUTH_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sk-your-apiclaw-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ANTHROPIC_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;"apiclaw/claude-sonnet-5.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;"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&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;Restart &lt;code&gt;claude&lt;/code&gt;, run &lt;code&gt;/status&lt;/code&gt;, and check that the base URL shows the gateway rather than &lt;code&gt;api.anthropic.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cursor:&lt;/strong&gt; in Settings, under Models, paste your key into the OpenAI API key field, turn on &lt;strong&gt;Override OpenAI Base URL&lt;/strong&gt; with &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;, and add a custom model such as &lt;code&gt;apiclaw/claude-sonnet-5.5&lt;/code&gt;. Keep the &lt;code&gt;apiclaw/&lt;/code&gt; prefix, because Cursor refuses custom models whose names collide with its built-in ones. Turn Auto off and disable the built-in models so chat actually goes to your key. If agent mode errors, use &lt;code&gt;https://apiclaw.biz/cursor&lt;/code&gt; as the base URL. Cursor's agent sends a Responses-style body to the chat completions path, and that endpoint accepts both shapes.&lt;/p&gt;

&lt;p&gt;To check the key outside both tools before you blame the editor, run the same call from Python:&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://apiclaw.biz/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;sk-your-apiclaw-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;reply&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;apiclaw/claude-sonnet-5.5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reply with the word ok.&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;5&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;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this works and the editor doesn't, the problem is the editor's config, not the key. I keep copy-paste configs for more tools (Cline, Continue, Codex CLI, Aider) in &lt;a href="https://github.com/ankita37105/apiclaw-examples" rel="noopener noreferrer"&gt;this examples repo&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Is there a flat-rate OpenRouter alternative that works with Claude Code?&lt;/strong&gt;&lt;br&gt;
Yes. Claude Code accepts any Anthropic-compatible endpoint through &lt;code&gt;ANTHROPIC_BASE_URL&lt;/code&gt;, so a flat-rate gateway that exposes one works. APIClaw does this with a daily request quota; MonoRouter does it by routing through a Claude subscription you already have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use OpenRouter-style custom models in Cursor without per-token billing?&lt;/strong&gt;&lt;br&gt;
For chat, yes. Override the OpenAI base URL with a flat-rate gateway's &lt;code&gt;/v1&lt;/code&gt; endpoint and add its model ID as a custom model. Tab completion still uses Cursor's own models, and Cursor Teams and Enterprise plans add Cursor's own charges on top.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is a flat-rate Claude API unlimited?&lt;/strong&gt;&lt;br&gt;
No, and be wary of anyone who says so. Flat plans cap something: requests per day (APIClaw), a dollar budget per month (Standard Compute), or the underlying subscription's usage windows (MonoRouter). What disappears is per-token metering, not limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many requests a day does Claude Code use?&lt;/strong&gt;&lt;br&gt;
It depends on how you work. Each tool step is a separate request, so a long agent session uses far more than chat does. Log a normal day through any gateway's dashboard before you pick a plan size.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is OpenRouter cheaper than a flat monthly plan?&lt;/strong&gt;&lt;br&gt;
For light or occasional use, usually yes. Flat plans win when you code with agents most days and long contexts would otherwise drive up the token count.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need a Claude Max subscription to use a gateway?&lt;/strong&gt;&lt;br&gt;
Not for APIClaw or Standard Compute, which sell API access directly. MonoRouter's model assumes you bring your own Claude subscription.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>cursor</category>
      <category>openrouter</category>
      <category>ai</category>
    </item>
    <item>
      <title>Running Inspect AI Evals on a Custom OpenAI-Compatible API: openai-api/ Model Names, Two Retry Layers and Hidden Errors</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Sun, 25 Oct 2026 08:46:52 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/running-inspect-ai-evals-on-a-custom-openai-compatible-api-openai-api-model-names-two-retry-1k9</link>
      <guid>https://dev.to/amankumar_apiclaw/running-inspect-ai-evals-on-a-custom-openai-compatible-api-openai-api-model-names-two-retry-1k9</guid>
      <description>&lt;p&gt;Inspect AI is the open-source evaluation framework from the UK AI Security Institute. You write a task (dataset, solver, scorer), run &lt;code&gt;inspect eval&lt;/code&gt;, and get a log you can browse. It has first-party providers for the big labs, plus a generic &lt;code&gt;openai-api&lt;/code&gt; provider for anything that speaks the OpenAI Chat Completions format: vLLM, a LiteLLM proxy, Ollama's &lt;code&gt;/v1&lt;/code&gt; endpoint or a hosted gateway.&lt;/p&gt;

&lt;p&gt;The setup is two environment variables, but a few defaults change your results and your request count in ways that are easy to miss. I tested inspect_ai 0.3.281 with openai 3.35.1 on Python 3.13.5 against a small local mock server. The mock logged the path, headers and JSON body of every request and could return 400, 401, 429 or 503 on demand. Everything below is what went over the wire. The examples use APIClaw, an OpenAI-compatible gateway I build, so weigh my opinions with that in mind. Its base URL is &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;. Replace &lt;code&gt;YOUR_MODEL_ID&lt;/code&gt; with an exact ID from your provider's model list rather than guessing one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model string picks your environment variables
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;inspect-ai openai

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APICLAW_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-key"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APICLAW_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://apiclaw.biz/v1"&lt;/span&gt;

inspect &lt;span class="nb"&gt;eval &lt;/span&gt;arith.py &lt;span class="nt"&gt;--model&lt;/span&gt; openai-api/apiclaw/YOUR_MODEL_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model string has three parts: &lt;code&gt;openai-api&lt;/code&gt;, a service name you choose, and the model ID. Inspect upper-cases the service name and reads &lt;code&gt;&amp;lt;SERVICE&amp;gt;_API_KEY&lt;/code&gt; and &lt;code&gt;&amp;lt;SERVICE&amp;gt;_BASE_URL&lt;/code&gt;. Hyphens become underscores, so &lt;code&gt;openai-api/my-gw/...&lt;/code&gt; reads &lt;code&gt;MY_GW_API_KEY&lt;/code&gt; and &lt;code&gt;MY_GW_BASE_URL&lt;/code&gt;. Pick a short name and stick with it, because it also appears in your logs and progress display.&lt;/p&gt;

&lt;p&gt;If either variable is missing you get a clear message before any request goes out: &lt;code&gt;No APICLAW_API_KEY defined in the environment.&lt;/code&gt; (or &lt;code&gt;..._BASE_URL&lt;/code&gt;). If you leave the service out entirely (&lt;code&gt;openai-api/YOUR_MODEL_ID&lt;/code&gt;), you get a &lt;code&gt;ValueError: openai-api model names must include a service prefix&lt;/code&gt; wrapped in a long TaskGroup traceback, which is easy to misread as a network problem.&lt;/p&gt;

&lt;p&gt;Everything after the service name is passed through as the model ID, slashes included. &lt;code&gt;openai-api/apiclaw/deepseek/deepseek-chat&lt;/code&gt; sent &lt;code&gt;"model": "deepseek/deepseek-chat"&lt;/code&gt;, which is what you want for gateways that use vendor-prefixed IDs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep /v1 in the base URL
&lt;/h2&gt;

&lt;p&gt;Inspect hands the base URL to the OpenAI Python SDK unchanged, and the SDK only appends &lt;code&gt;/chat/completions&lt;/code&gt;. With &lt;code&gt;APICLAW_BASE_URL=http://host/v1&lt;/code&gt; the mock saw &lt;code&gt;POST /v1/chat/completions&lt;/code&gt;. Without &lt;code&gt;/v1&lt;/code&gt; it saw &lt;code&gt;POST /chat/completions&lt;/code&gt;, which most servers answer with a 404. The request carried &lt;code&gt;Authorization: Bearer &amp;lt;your key&amp;gt;&lt;/code&gt; and the SDK's &lt;code&gt;AsyncOpenAI/Python&lt;/code&gt; user agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a default request contains
&lt;/h2&gt;

&lt;p&gt;Here is the task I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# arith.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;inspect_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;inspect_ai.dataset&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Sample&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;inspect_ai.scorer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;inspect_ai.solver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;

&lt;span class="nd"&gt;@task&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;arith&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is 2+2? (variant &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
        &lt;span class="n"&gt;solver&lt;/span&gt;&lt;span class="o"&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;scorer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;match&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;With no generation options, the body was just &lt;code&gt;model&lt;/code&gt; and &lt;code&gt;messages&lt;/code&gt;. No temperature, no &lt;code&gt;max_tokens&lt;/code&gt;, no seed, so you get whatever defaults the server applies. If you want reproducible runs, say so on the command line: &lt;code&gt;--temperature 0 --max-tokens 50 --seed 7&lt;/code&gt; arrived as &lt;code&gt;"temperature": 0.0, "max_tokens": 50, "seed": 7&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Streaming is off unless you ask for it. &lt;code&gt;-M stream=true&lt;/code&gt; added &lt;code&gt;"stream": true&lt;/code&gt; and &lt;code&gt;"stream_options": {"include_usage": true}&lt;/code&gt;, and token counts still showed up in the summary because the mock sent a usage chunk at the end. If your server does not send usage when streaming, expect missing token totals.&lt;/p&gt;

&lt;p&gt;If the model wraps its reasoning in &lt;code&gt;&amp;lt;think&amp;gt;...&amp;lt;/think&amp;gt;&lt;/code&gt;, Inspect splits it out. The mock answered &lt;code&gt;&amp;lt;think&amp;gt;let me reason&amp;lt;/think&amp;gt;ANSWER: 4&lt;/code&gt;, and the stored message had a reasoning block plus a text block, with &lt;code&gt;output.completion&lt;/code&gt; equal to &lt;code&gt;ANSWER: 4&lt;/code&gt;. The &lt;code&gt;match()&lt;/code&gt; scorer saw only the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrency is adaptive by default
&lt;/h2&gt;

&lt;p&gt;Inspect does not send one request at a time. Adaptive concurrency is on by default; the config docstring gives its bounds as a minimum of 10, a start of 20 and a maximum of 100 connections. With 60 samples and a mock that took 300 ms per reply, I saw up to 30 requests in flight at once.&lt;/p&gt;

&lt;p&gt;That matters if your provider limits requests per minute or per day, which is how many flat-rate plans work. Set a fixed number instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;inspect &lt;span class="nb"&gt;eval &lt;/span&gt;arith.py &lt;span class="nt"&gt;--model&lt;/span&gt; openai-api/apiclaw/YOUR_MODEL_ID &lt;span class="nt"&gt;--max-connections&lt;/span&gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;--max-connections 4&lt;/code&gt; the peak was exactly 4. Also count your requests honestly: every sample is at least one call, and model-graded scorers add more (see below).&lt;/p&gt;

&lt;h2&gt;
  
  
  Two retry layers multiply
&lt;/h2&gt;

&lt;p&gt;This was the biggest surprise. Inspect creates an &lt;code&gt;AsyncOpenAI&lt;/code&gt; client and leaves the SDK's own &lt;code&gt;max_retries&lt;/code&gt; at its default of 2, so every Inspect attempt is up to three HTTP requests. Inspect then retries failed attempts itself, and its &lt;code&gt;max_retries&lt;/code&gt; defaults to unlimited.&lt;/p&gt;

&lt;p&gt;With the mock returning 429 and &lt;code&gt;Retry-After: 1&lt;/code&gt; for one sample:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--max-retries 3&lt;/code&gt; sent 12 requests over about 37 seconds (4 Inspect attempts times 3 SDK attempts; the &lt;code&gt;x-stainless-retry-count&lt;/code&gt; header went 0, 1, 2 four times).&lt;/li&gt;
&lt;li&gt;With no limits set, it had sent 15 requests after 75 seconds and was still going when I killed it. The gaps between Inspect's attempts grew from about 3 to 9, 13 and 26 seconds.&lt;/li&gt;
&lt;li&gt;503 behaved the same as 429. A 401 or 400 was sent once and not retried.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get one retry layer you control, turn the SDK's off with a model arg and give Inspect a limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;inspect &lt;span class="nb"&gt;eval &lt;/span&gt;arith.py &lt;span class="nt"&gt;--model&lt;/span&gt; openai-api/apiclaw/YOUR_MODEL_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-M&lt;/span&gt; &lt;span class="nv"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nt"&gt;--max-retries&lt;/span&gt; 3 &lt;span class="nt"&gt;--timeout&lt;/span&gt; 120
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-M&lt;/code&gt; arguments go to the OpenAI client constructor, so &lt;code&gt;max_retries=0&lt;/code&gt; applies there. With that and &lt;code&gt;--max-retries 3&lt;/code&gt; the same 429 produced 4 requests, not 12. &lt;code&gt;--timeout&lt;/code&gt; caps the whole request including retries; with &lt;code&gt;--timeout 20&lt;/code&gt; the run stopped after 4 requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  One bad request fails the whole eval, unless you let it hide
&lt;/h2&gt;

&lt;p&gt;I made the mock return a 400 for one sample out of five. By default the eval ended with status &lt;code&gt;error&lt;/code&gt; and no scores at all, even though four samples had succeeded.&lt;/p&gt;

&lt;p&gt;The usual fix is &lt;code&gt;--fail-on-error 0.25&lt;/code&gt; (tolerate up to 25% failed samples) or &lt;code&gt;--no-fail-on-error&lt;/code&gt;. Both gave status &lt;code&gt;success&lt;/code&gt; and &lt;code&gt;accuracy 1.000&lt;/code&gt;. That number is computed over the four samples that worked; the failed one is left out rather than counted as wrong. If a server rejects your hardest prompts, for example because they exceed the context window, your accuracy goes up. Check the errored sample count in the log before you compare models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;inspect_ai.log&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;read_eval_log&lt;/span&gt;

&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_eval_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;logs/your-run.eval&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;errored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;samples&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="n"&gt;error&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;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&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;errored&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; samples errored&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;h2&gt;
  
  
  The grader is the model you are testing
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;model_graded_qa()&lt;/code&gt; and the other model-graded scorers use the &lt;code&gt;grader&lt;/code&gt; model role, and if you do not set it they use the model under evaluation. In my run each sample sent two requests to the same model: the answer, then a grading prompt starting "You are assessing a submitted answer...". Letting a model grade itself is rarely what you want, and it doubles your request count. Point the grader somewhere else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;inspect &lt;span class="nb"&gt;eval &lt;/span&gt;graded.py &lt;span class="nt"&gt;--model&lt;/span&gt; openai-api/apiclaw/YOUR_MODEL_ID &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model-role&lt;/span&gt; &lt;span class="nv"&gt;grader&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openai-api/apiclaw/YOUR_GRADER_MODEL_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that set, the mock saw the answer request go to one model ID and the grading request to the other. Both use the same &lt;code&gt;APICLAW_*&lt;/code&gt; variables because they share a service name.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same settings from Python
&lt;/h2&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;inspect_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;arith&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;arith&lt;/span&gt;

&lt;span class="n"&gt;logs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;arith&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-api/apiclaw/YOUR_MODEL_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model_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://apiclaw.biz/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;model_args&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;max_retries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;max_retries&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;max_connections&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&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;logs&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;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;model_base_url&lt;/code&gt; replaces the &lt;code&gt;_BASE_URL&lt;/code&gt; variable; the key still comes from &lt;code&gt;APICLAW_API_KEY&lt;/code&gt;. For one-off calls outside an eval, &lt;code&gt;get_model("openai-api/apiclaw/YOUR_MODEL_ID", base_url=..., api_key=...)&lt;/code&gt; and &lt;code&gt;await model.generate("...")&lt;/code&gt; worked the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ends up in the logs
&lt;/h2&gt;

&lt;p&gt;Inspect writes a &lt;code&gt;.eval&lt;/code&gt; file for every run, including failed ones, and it stores each request's messages and parameters so you can inspect them in &lt;code&gt;inspect view&lt;/code&gt;. I searched all 18 logs from my tests for the API key and for the string &lt;code&gt;Bearer&lt;/code&gt; and found neither. Prompts and responses are stored in full, so treat the &lt;code&gt;logs/&lt;/code&gt; folder like any other file with test data in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;openai-api/&amp;lt;service&amp;gt;/&amp;lt;model&amp;gt;&lt;/code&gt; and set &lt;code&gt;&amp;lt;SERVICE&amp;gt;_API_KEY&lt;/code&gt; and &lt;code&gt;&amp;lt;SERVICE&amp;gt;_BASE_URL&lt;/code&gt;, with &lt;code&gt;/v1&lt;/code&gt; in the URL.&lt;/li&gt;
&lt;li&gt;Pass &lt;code&gt;--temperature&lt;/code&gt; and &lt;code&gt;--seed&lt;/code&gt; explicitly; nothing is sent by default.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;--max-connections&lt;/code&gt; if your plan limits requests.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;-M max_retries=0&lt;/code&gt; with &lt;code&gt;--max-retries N&lt;/code&gt; and &lt;code&gt;--timeout&lt;/code&gt;, or a 429 can retry for a long time.&lt;/li&gt;
&lt;li&gt;After a run with &lt;code&gt;--fail-on-error&lt;/code&gt; or &lt;code&gt;--no-fail-on-error&lt;/code&gt;, count errored samples before trusting accuracy.&lt;/li&gt;
&lt;li&gt;Give model-graded scorers their own grader with &lt;code&gt;--model-role grader=...&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, the OpenAI-compatible gateway used in these examples (flat monthly plans; crypto on the site, other payment methods through support). Everything above applies to any compatible endpoint.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pythonllmaitesting</category>
    </item>
    <item>
      <title>Using CloudWeGo Eino With a Custom OpenAI-Compatible API in Go: BaseURL, Zero Retries and a 12-Step Agent Limit</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Mon, 19 Oct 2026 19:46:49 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/using-cloudwego-eino-with-a-custom-openai-compatible-api-in-go-baseurl-zero-retries-and-a-12-step-p80</link>
      <guid>https://dev.to/amankumar_apiclaw/using-cloudwego-eino-with-a-custom-openai-compatible-api-in-go-baseurl-zero-retries-and-a-12-step-p80</guid>
      <description>&lt;p&gt;Eino is CloudWeGo's Go framework for LLM applications: chat models, tools, graphs and a ReAct agent, in the style of LangChain but written for Go. Its OpenAI component (&lt;code&gt;github.com/cloudwego/eino-ext/components/model/openai&lt;/code&gt;) is the one most people use with self-hosted or hosted OpenAI-compatible servers such as vLLM, Ollama's &lt;code&gt;/v1&lt;/code&gt; endpoint, LiteLLM or a gateway.&lt;/p&gt;

&lt;p&gt;The setup is three fields. The behaviour around them is less obvious, so I tested eino v0.7.13 and the eino-ext OpenAI component v0.1.13 on Go 1.27.2 against a small local mock server. The mock logged the path, headers and JSON body of every request and could return 401, 400, 429, 500 or 503 on demand, or keep asking for a tool call forever. Everything below is what went over the wire. The examples use APIClaw, an OpenAI-compatible gateway I build, so weigh my opinions with that in mind. Its base URL is &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;. Replace &lt;code&gt;YOUR_MODEL_ID&lt;/code&gt; with an exact ID from your provider's model list rather than guessing one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install, and one build error you may hit
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/cloudwego/eino@latest
go get github.com/cloudwego/eino-ext/components/model/openai@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Go 1.27 my first &lt;code&gt;go build&lt;/code&gt; failed inside &lt;code&gt;github.com/bytedance/sonic/internal/rt&lt;/code&gt; with &lt;code&gt;undefined: GoMapIterator&lt;/code&gt;. Eino pulled in sonic v1.14.1, which does not build on that toolchain. Upgrading sonic fixed it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/bytedance/sonic@latest github.com/bytedance/sonic/loader@latest
go mod tidy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That moved me to sonic v1.15.4 and everything compiled. If you are on an older Go release you may never see this.&lt;/p&gt;

&lt;h2&gt;
  
  
  The minimal config
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/cloudwego/eino-ext/components/model/openai"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/cloudwego/eino/schema"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewChatModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatModelConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;BaseURL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://apiclaw.biz/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;APIKey&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"APICLAW_API_KEY"&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="s"&gt;"YOUR_MODEL_ID"&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="m"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&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;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SystemMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Be brief."&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Say hi"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The struct comments say &lt;code&gt;BaseURL&lt;/code&gt; is for Azure, but it is used for every non-Azure client too. Eino does not read &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; or &lt;code&gt;OPENAI_BASE_URL&lt;/code&gt; from the environment, so pass both explicitly.&lt;/p&gt;

&lt;p&gt;Three things I checked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The path is &lt;code&gt;BaseURL&lt;/code&gt; + &lt;code&gt;/chat/completions&lt;/code&gt;, nothing more.&lt;/strong&gt; &lt;code&gt;https://host/v1&lt;/code&gt; and &lt;code&gt;https://host/v1/&lt;/code&gt; both produced &lt;code&gt;POST /v1/chat/completions&lt;/code&gt;. A bare &lt;code&gt;https://host&lt;/code&gt; produced &lt;code&gt;POST /chat/completions&lt;/code&gt;, which most gateways answer with a 404. Keep the &lt;code&gt;/v1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The body is minimal.&lt;/strong&gt; With only the fields above, the request was &lt;code&gt;{"messages":[...],"model":"YOUR_MODEL_ID"}&lt;/code&gt;. No temperature, no &lt;code&gt;max_tokens&lt;/code&gt;, no &lt;code&gt;stream:false&lt;/code&gt;. Headers were &lt;code&gt;Authorization: Bearer &amp;lt;key&amp;gt;&lt;/code&gt; and Go's default &lt;code&gt;User-Agent: Go-http-client/1.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Timeout&lt;/code&gt; defaults to none.&lt;/strong&gt; The struct comment says so, and nothing else in the chain adds one. If you leave it unset and the upstream stalls, &lt;code&gt;Generate&lt;/code&gt; waits as long as your context allows. If you pass your own &lt;code&gt;HTTPClient&lt;/code&gt;, &lt;code&gt;Timeout&lt;/code&gt; is ignored and the client's timeout applies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sampling options are pointers, so zero really is sent
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Temperature&lt;/code&gt;, &lt;code&gt;MaxTokens&lt;/code&gt;, &lt;code&gt;TopP&lt;/code&gt; and friends are pointer fields. Setting &lt;code&gt;Temperature: &amp;amp;zero&lt;/code&gt; put &lt;code&gt;"temperature":0&lt;/code&gt; in the body, which some Python wrappers drop because they treat zero as "unset". Per-call options override the config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTemperature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OTHER_MODEL_ID"&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 call sent &lt;code&gt;"temperature":0.7&lt;/code&gt; and &lt;code&gt;"model":"OTHER_MODEL_ID"&lt;/code&gt; while keeping the configured &lt;code&gt;max_tokens&lt;/code&gt;. &lt;code&gt;model.WithModel&lt;/code&gt; is a cheap way to try a second model on the same gateway without building another client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming asks for usage automatically
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cm.Stream(ctx, msgs)&lt;/code&gt; sent &lt;code&gt;"stream":true&lt;/code&gt; and &lt;code&gt;"stream_options":{"include_usage":true}&lt;/code&gt; without being asked. After concatenating the chunks with &lt;code&gt;schema.ConcatMessages&lt;/code&gt;, &lt;code&gt;ResponseMeta.Usage&lt;/code&gt; held the prompt, completion and total token counts from the final usage chunk.&lt;/p&gt;

&lt;p&gt;If your server rejects unknown fields like &lt;code&gt;stream_options&lt;/code&gt;, that is the first thing to check when streaming fails but &lt;code&gt;Generate&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;For reasoning models, a &lt;code&gt;reasoning_content&lt;/code&gt; field in the response landed in &lt;code&gt;out.ReasoningContent&lt;/code&gt;. Inline &lt;code&gt;&amp;lt;think&amp;gt;...&amp;lt;/think&amp;gt;&lt;/code&gt; text stayed inside &lt;code&gt;out.Content&lt;/code&gt;; Eino does not strip it, so do that yourself if your model emits it.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are no retries
&lt;/h2&gt;

&lt;p&gt;This surprised me most. Every error status got exactly one request and came back in a millisecond or two:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server response&lt;/th&gt;
&lt;th&gt;Requests sent&lt;/th&gt;
&lt;th&gt;Returned error&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;401&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;status code: 401 ... message: ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;same shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;429 with &lt;code&gt;Retry-After: 2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;same shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500 / 503&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;same shape&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Retry-After&lt;/code&gt; is ignored because nothing retries. That is fine for a CLI. For a service sitting behind a gateway that rate-limits per minute, one 429 becomes a user-visible failure.&lt;/p&gt;

&lt;p&gt;The error can be inspected with &lt;code&gt;errors.As&lt;/code&gt; against the eino-ext type, not the underlying go-openai fork's type. I tried both. The fork's &lt;code&gt;*APIError&lt;/code&gt; did not match, because the component converts it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiErr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APIError&lt;/span&gt; &lt;span class="c"&gt;// github.com/cloudwego/eino-ext/components/model/openai&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;apiErr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;apiErr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPStatusCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;429&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// back off&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That still matched when the 429 happened inside a ReAct agent run, where the outer error text starts with &lt;code&gt;[NodeRunError]&lt;/code&gt; and names the node path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding retries with an http.RoundTripper
&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;ChatModelConfig&lt;/code&gt; accepts an &lt;code&gt;*http.Client&lt;/code&gt;, the cleanest fix is a transport that replays the request body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;retryTransport&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;base&lt;/span&gt;     &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RoundTripper&lt;/span&gt;
    &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;retryTransport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;RoundTrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&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;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;var&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NopCloser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&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;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RoundTrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&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;StatusCode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;429&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;StatusCode&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempts&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&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="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&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;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Retry-After"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&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;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewChatModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChatModelConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;BaseURL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://apiclaw.biz/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;APIKey&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"APICLAW_API_KEY"&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="s"&gt;"YOUR_MODEL_ID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;HTTPClient&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&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;Timeout&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="m"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;retryTransport&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultTransport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Against the mock, a server that returned 429 twice and then succeeded produced three requests about two seconds apart in total and a normal reply. A permanent 503 produced three requests and then the usual error. A 401 still produced one request, which is what you want. Note that &lt;code&gt;http.Client.Timeout&lt;/code&gt; covers all attempts together, so size it for the retries. Retrying a streaming call this way only helps when the error arrives before the first byte, which is where 429s usually happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ReAct agent stops at MaxStep, and steps are not tool calls
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AgentConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ToolCallingModel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ToolsConfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToolsNodeConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Tools&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseTool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
    &lt;span class="n"&gt;MaxStep&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="m"&gt;20&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;With a tool built by &lt;code&gt;utils.InferTool&lt;/code&gt;, the tool schema went out with &lt;code&gt;"additionalProperties":false&lt;/code&gt; and a &lt;code&gt;required&lt;/code&gt; list, plus &lt;code&gt;"tool_choice":"auto"&lt;/code&gt;. There was no &lt;code&gt;strict&lt;/code&gt; flag. The assistant message that carried the tool call was sent back with no &lt;code&gt;content&lt;/code&gt; key at all, followed by a &lt;code&gt;role: tool&lt;/code&gt; message with the matching &lt;code&gt;tool_call_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To see the limit, I made the mock request a tool call on every turn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With &lt;code&gt;MaxStep&lt;/code&gt; unset (default 12), the run made &lt;strong&gt;7 model requests and 6 tool calls&lt;/strong&gt;, then returned &lt;code&gt;[GraphRunError] exceeds max steps&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;MaxStep: 40&lt;/code&gt;, it made 20 model requests and 20 tool calls before the same error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;MaxStep&lt;/code&gt; counts graph node executions, and each round is a model node plus a tools node, so you get roughly &lt;code&gt;MaxStep / 2&lt;/code&gt; tool calls, not &lt;code&gt;MaxStep&lt;/code&gt;. Each request also re-sends the whole history, so the last request in the 40-step run carried 39 messages. Check for the limit with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrExceedMaxSteps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// the model kept calling tools; surface a partial answer or ask the user&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the mock returned a tool call once and then plain text, the agent finished normally after two requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;BaseURL&lt;/code&gt; with &lt;code&gt;/v1&lt;/code&gt;; Eino only appends &lt;code&gt;/chat/completions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pass &lt;code&gt;APIKey&lt;/code&gt; explicitly; environment variables are not read.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;Timeout&lt;/code&gt; or your own &lt;code&gt;HTTPClient&lt;/code&gt;; the default is no timeout.&lt;/li&gt;
&lt;li&gt;Add retries yourself with a transport, and match errors with the eino-ext &lt;code&gt;*openai.APIError&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Expect &lt;code&gt;stream_options.include_usage&lt;/code&gt; on every stream.&lt;/li&gt;
&lt;li&gt;Treat &lt;code&gt;MaxStep&lt;/code&gt; as about twice the number of tool rounds you want to allow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, the OpenAI-compatible gateway used in these examples (flat monthly plans; crypto on the site, other payment methods through support). Everything above applies to any compatible endpoint.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>llm</category>
      <category>ai</category>
      <category>openai</category>
    </item>
    <item>
      <title>Google's LangExtract on a Custom OpenAI-Compatible API: Model IDs That Route to Ollama, Strict Schemas and Silent Chunks</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Mon, 19 Oct 2026 07:38:16 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/googles-langextract-on-a-custom-openai-compatible-api-model-ids-that-route-to-ollama-strict-8dd</link>
      <guid>https://dev.to/amankumar_apiclaw/googles-langextract-on-a-custom-openai-compatible-api-model-ids-that-route-to-ollama-strict-8dd</guid>
      <description>&lt;p&gt;LangExtract is Google's Python library for pulling structured entities out of long text, with every extraction mapped back to its character position in the source. You describe the task, give one or two examples, and it chunks the document, sends each chunk to a model, parses the JSON and aligns the results. Gemini is the default, but it has an OpenAI provider built on the official OpenAI SDK, so it can run against vLLM, LiteLLM or a hosted gateway.&lt;/p&gt;

&lt;p&gt;Getting it to use that provider with a non-OpenAI model name is the first surprise. I tested langextract 1.7.1 (openai 3.35.1, Python 3.13) against a small local mock server that logged every request and could return 400, 429, 503, fenced JSON or truncated output on demand. Everything below is what went over the wire. The examples point at APIClaw, an OpenAI-compatible gateway I build, so weigh my opinions accordingly. Its base URL is &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;; replace &lt;code&gt;YOUR_MODEL_ID&lt;/code&gt; with an exact ID from your provider's model list.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model name chooses the provider
&lt;/h2&gt;

&lt;p&gt;The obvious call is:&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;langextract&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;text_or_documents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prompt_description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3-coder-plus&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-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;model_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://apiclaw.biz/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;LangExtract routes on regex patterns over &lt;code&gt;model_id&lt;/code&gt;. Only names starting with &lt;code&gt;gpt-3.5&lt;/code&gt;, &lt;code&gt;gpt-4&lt;/code&gt;, &lt;code&gt;gpt-5&lt;/code&gt; or &lt;code&gt;o1&lt;/code&gt; to &lt;code&gt;o9&lt;/code&gt; go to the OpenAI provider. Names starting with &lt;code&gt;qwen&lt;/code&gt;, &lt;code&gt;deepseek&lt;/code&gt;, &lt;code&gt;llama&lt;/code&gt;, &lt;code&gt;mistral&lt;/code&gt;, &lt;code&gt;gemma&lt;/code&gt;, &lt;code&gt;phi&lt;/code&gt; and &lt;code&gt;gpt-oss&lt;/code&gt;, among others, go to the &lt;strong&gt;Ollama&lt;/strong&gt; provider. Here is what happened in my tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;qwen3-coder-plus&lt;/code&gt; and &lt;code&gt;gpt-oss-120b&lt;/code&gt; went to the Ollama client, which POSTed to &lt;code&gt;/v1/api/generate&lt;/code&gt; on my base URL and failed with &lt;code&gt;Can't find Ollama qwen3-coder-plus. Try: ollama run qwen3-coder-plus&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A name that matched nothing, such as &lt;code&gt;plain-model&lt;/code&gt;, failed with &lt;code&gt;No provider registered for model_id='plain-model'&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gpt-4o-mini&lt;/code&gt; with &lt;code&gt;model_url&lt;/code&gt; worked and hit &lt;code&gt;/v1/chat/completions&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the code above only works if your gateway's model happens to be named like an OpenAI model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Force the OpenAI provider with ModelConfig
&lt;/h2&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;import&lt;/span&gt; &lt;span class="n"&gt;langextract&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ModelConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&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_MODEL_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OpenAILanguageModel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# "openai" also worked
&lt;/span&gt;    &lt;span class="n"&gt;provider_kwargs&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;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;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;APICLAW_API_KEY&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;base_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;https://apiclaw.biz/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_output_tokens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_workers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;text_or_documents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prompt_description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract every person mentioned, with their role. Use exact text.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;show_progress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extractions&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extraction_class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extraction_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;char_interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sent &lt;code&gt;POST /v1/chat/completions&lt;/code&gt; for every model name I tried. Two details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pass &lt;code&gt;api_key&lt;/code&gt; explicitly.&lt;/strong&gt; LangExtract only reads &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; from the environment when the model ID contains &lt;code&gt;gpt&lt;/code&gt;. With an explicit provider and a name like &lt;code&gt;qwen3-coder-plus&lt;/code&gt;, leaving the key out failed with &lt;code&gt;API key not provided.&lt;/code&gt; even though &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; was set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;base_url&lt;/code&gt; can come from the environment.&lt;/strong&gt; With &lt;code&gt;base_url&lt;/code&gt; omitted, the SDK picked up &lt;code&gt;OPENAI_BASE_URL&lt;/code&gt;. Keep &lt;code&gt;/v1&lt;/code&gt; on the end either way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll also see a warning: &lt;code&gt;With 'config', schema constraints are still applied via examples.&lt;/code&gt; That matters for the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each request contains
&lt;/h2&gt;

&lt;p&gt;Every chunk became one request with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a system message, &lt;code&gt;You are a helpful assistant that responds in JSON format.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;one user message holding your prompt description, your examples as &lt;code&gt;Q:&lt;/code&gt;/&lt;code&gt;A:&lt;/code&gt; pairs with the expected JSON, and the chunk text,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;n: 1&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;response_format&lt;/code&gt; of type &lt;code&gt;json_schema&lt;/code&gt;, named &lt;code&gt;langextract_extractions&lt;/code&gt;, with &lt;code&gt;strict: true&lt;/code&gt;, built from your examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default there was &lt;strong&gt;no &lt;code&gt;temperature&lt;/code&gt; and no &lt;code&gt;max_tokens&lt;/code&gt;&lt;/strong&gt;, so the server's defaults applied. Setting &lt;code&gt;temperature&lt;/code&gt; and &lt;code&gt;max_output_tokens&lt;/code&gt; in &lt;code&gt;provider_kwargs&lt;/code&gt; sent &lt;code&gt;temperature: 0.0&lt;/code&gt; and &lt;code&gt;max_tokens: 2000&lt;/code&gt;. For extraction I'd always set both: a low temperature for consistency and an output cap that fits a long list of entities.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the server doesn't support json_schema
&lt;/h2&gt;

&lt;p&gt;Strict &lt;code&gt;json_schema&lt;/code&gt; output is not universal. Some models and some OpenAI-compatible servers support only &lt;code&gt;json_object&lt;/code&gt;, or nothing. My mock returned a 400 for &lt;code&gt;json_schema&lt;/code&gt;, and the whole &lt;code&gt;extract()&lt;/code&gt; call raised &lt;code&gt;InferenceRuntimeError: OpenAI API error: Error code: 400&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_schema_constraints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;use_schema_constraints=False&lt;/code&gt; the request switched to &lt;code&gt;response_format: {"type": "json_object"}&lt;/code&gt; and succeeded. The examples in the prompt still show the model the expected shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parse failures are dropped with a warning
&lt;/h2&gt;

&lt;p&gt;This is the setting I'd change first. By default LangExtract suppresses parse errors per chunk. Each of these runs printed one log line and returned &lt;strong&gt;zero extractions with no exception&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The model wrapped its answer in prose and a fence (&lt;code&gt;Here is the result:&lt;/code&gt; followed by a fenced json block). Under &lt;code&gt;json_object&lt;/code&gt; mode LangExtract expects raw JSON, so the chunk was omitted: &lt;code&gt;Chunk omitted from results (parse error): Failed to parse JSON content&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The reply was cut off with &lt;code&gt;finish_reason: "length"&lt;/code&gt;. The truncated JSON failed to parse and the chunk was dropped the same way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a 40-chunk document, a few dropped chunks look like the model just didn't find anything there. Two fixes:&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;use_schema_constraints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;fence_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                  &lt;span class="c1"&gt;# accept fenced json replies
&lt;/span&gt;    &lt;span class="n"&gt;resolver_params&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;suppress_parse_errors&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;   &lt;span class="c1"&gt;# fail loudly instead
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fence_output=True&lt;/code&gt; parsed the fenced reply correctly. &lt;code&gt;suppress_parse_errors: False&lt;/code&gt; turned the silent drop into a &lt;code&gt;ResolverParsingError&lt;/code&gt;, which you can catch and retry. A reply that started with a &lt;code&gt;&amp;lt;think&amp;gt;...&amp;lt;/think&amp;gt;&lt;/code&gt; block parsed fine in my test, so reasoning models weren't a problem there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chunks, workers and passes multiply requests
&lt;/h2&gt;

&lt;p&gt;I ran a 5,320-character document with the defaults:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Requests&lt;/th&gt;
&lt;th&gt;Max in flight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;defaults (&lt;code&gt;max_char_buffer=1000&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;max_workers: 3&lt;/code&gt; in &lt;code&gt;provider_kwargs&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extraction_passes=3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;max_char_buffer=4000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each request repeats your prompt description and examples, so with small chunks the fixed part can be a large share of every request. &lt;code&gt;max_workers&lt;/code&gt; defaults to 10, which means a long document can fire 10 requests at once. On a plan with a per-minute or concurrency limit, set it lower. &lt;code&gt;extraction_passes&lt;/code&gt; runs the whole document again per pass, one pass after another, so three passes triple both requests and time.&lt;/p&gt;

&lt;p&gt;A larger &lt;code&gt;max_char_buffer&lt;/code&gt; cuts request count, but long chunks give the model more to track, so test recall on your own documents before raising it a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retries come from the SDK only
&lt;/h2&gt;

&lt;p&gt;A server that always returned 503 got three requests (the SDK's default two retries) and then &lt;code&gt;extract()&lt;/code&gt; raised &lt;code&gt;InferenceRuntimeError&lt;/code&gt;. A 429 with &lt;code&gt;Retry-After: 2&lt;/code&gt; was honoured: the SDK waited and the third request succeeded after about 4.6 seconds. LangExtract adds no retry loop of its own, so for big batch jobs wrap the call in your own retry, and remember that a failure in one chunk fails the whole document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;ModelConfig(provider="OpenAILanguageModel")&lt;/code&gt; unless your model ID starts with &lt;code&gt;gpt-&lt;/code&gt; or &lt;code&gt;o1&lt;/code&gt; to &lt;code&gt;o9&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pass &lt;code&gt;api_key&lt;/code&gt; in &lt;code&gt;provider_kwargs&lt;/code&gt;; the env key is only read for &lt;code&gt;gpt&lt;/code&gt; model names.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;temperature&lt;/code&gt; and &lt;code&gt;max_output_tokens&lt;/code&gt; yourself.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;use_schema_constraints=False&lt;/code&gt; if your server rejects &lt;code&gt;json_schema&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;suppress_parse_errors: False&lt;/code&gt; (and &lt;code&gt;fence_output=True&lt;/code&gt; for chatty models) so dropped chunks don't go unnoticed.&lt;/li&gt;
&lt;li&gt;Lower &lt;code&gt;max_workers&lt;/code&gt; to fit your rate limit, and count &lt;code&gt;extraction_passes&lt;/code&gt; as a multiplier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, the OpenAI-compatible gateway in these examples (flat monthly plans; crypto on the site, other payment methods through support). Everything above applies to any compatible endpoint.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>llm</category>
      <category>nlp</category>
      <category>openai</category>
    </item>
    <item>
      <title>Running Qwen Code on a Custom OpenAI-Compatible API: modelProviders, a 41,000-Character First Request and Retries That Keep Going for Minutes</title>
      <dc:creator>Aman Kumar</dc:creator>
      <pubDate>Sun, 18 Oct 2026 21:48:11 +0000</pubDate>
      <link>https://dev.to/amankumar_apiclaw/running-qwen-code-on-a-custom-openai-compatible-api-modelproviders-a-41000-character-first-4kjl</link>
      <guid>https://dev.to/amankumar_apiclaw/running-qwen-code-on-a-custom-openai-compatible-api-modelproviders-a-41000-character-first-4kjl</guid>
      <description>&lt;p&gt;Qwen Code is the terminal coding agent from the Qwen team. It started as a fork of Gemini CLI, but unlike Gemini CLI it speaks the OpenAI Chat Completions format, so it can run against any OpenAI-compatible server: vLLM, Ollama's &lt;code&gt;/v1&lt;/code&gt; endpoint, LiteLLM, or a hosted gateway.&lt;/p&gt;

&lt;p&gt;Setup is simple. A few defaults are less obvious, so I tested Qwen Code 0.25.2 on Node 20.19.2 against a small local mock server that logged every request and could return 401, 429 with &lt;code&gt;Retry-After&lt;/code&gt;, or 503 on demand. Everything below is what went over the wire. The examples point at APIClaw, an OpenAI-compatible gateway I build, so weigh my opinions accordingly. Its base URL is &lt;code&gt;https://apiclaw.biz/v1&lt;/code&gt;; replace &lt;code&gt;YOUR_MODEL_ID&lt;/code&gt; with an exact ID from your provider's model list.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quickest setup: three environment variables
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @qwen-code/qwen-code
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-key"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://apiclaw.biz/v1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MODEL_ID"&lt;/span&gt;
qwen &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Explain what this repo's Makefile does"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was enough. With no settings file at all, Qwen Code picked the OpenAI-compatible route and sent &lt;code&gt;POST /v1/chat/completions&lt;/code&gt; with &lt;code&gt;Authorization: Bearer ...&lt;/code&gt;, &lt;code&gt;stream: true&lt;/code&gt;, &lt;code&gt;stream_options: {"include_usage": true}&lt;/code&gt; and a tool list.&lt;/p&gt;

&lt;p&gt;Two details matter here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep &lt;code&gt;/v1&lt;/code&gt; in the base URL.&lt;/strong&gt; Qwen Code uses the official OpenAI Node SDK, which appends &lt;code&gt;/chat/completions&lt;/code&gt; to whatever you give it. With &lt;code&gt;OPENAI_BASE_URL=https://host&lt;/code&gt; the request went to &lt;code&gt;/chat/completions&lt;/code&gt; with no &lt;code&gt;/v1&lt;/code&gt;, which most gateways answer with a 404.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;max_tokens&lt;/code&gt; is 32000 by default.&lt;/strong&gt; Every request in my env-only runs carried &lt;code&gt;"max_tokens": 32000&lt;/code&gt;. Some servers reject a value above the model's output limit, and others reserve that much against your quota. If your model's output cap is lower, set it yourself (below).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A wrong key failed cleanly: one request, &lt;code&gt;[API Error: 401 Invalid API key]&lt;/code&gt;, exit code 1, no retries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup I'd actually use: modelProviders in settings.json
&lt;/h2&gt;

&lt;p&gt;Environment variables create what the docs call a "runtime model." For anything you use daily, a provider entry in &lt;code&gt;~/.qwen/settings.json&lt;/code&gt; is easier to reason about:&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;"modelProviders"&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;"openai"&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="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;"YOUR_MODEL_ID"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gateway 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;"envKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"APICLAW_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&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://apiclaw.biz/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"generationConfig"&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;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"maxRetries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"contextWindowSize"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"samplingParams"&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;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4096&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;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="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"security"&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;"auth"&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;"selectedType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai"&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;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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_MODEL_ID"&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;The key under &lt;code&gt;modelProviders&lt;/code&gt; must be a real protocol name (&lt;code&gt;openai&lt;/code&gt;, &lt;code&gt;anthropic&lt;/code&gt;, &lt;code&gt;gemini&lt;/code&gt;, &lt;code&gt;vertex-ai&lt;/code&gt;). A made-up key like &lt;code&gt;"apiclaw"&lt;/code&gt; is skipped with a warning unless you also map it in a top-level &lt;code&gt;providerProtocol&lt;/code&gt; block. &lt;code&gt;envKey&lt;/code&gt; is the &lt;em&gt;name&lt;/em&gt; of an environment variable, not the key itself. I tested three places for it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;APICLAW_API_KEY=...&lt;/code&gt; in a &lt;code&gt;.env&lt;/code&gt; file in the project directory worked.&lt;/li&gt;
&lt;li&gt;The same line in &lt;code&gt;~/.qwen/.env&lt;/code&gt; worked.&lt;/li&gt;
&lt;li&gt;With neither, Qwen Code stopped before sending anything: &lt;code&gt;Missing API key for OpenAI-compatible auth. Set the 'APICLAW_API_KEY' environment variable.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you use a project &lt;code&gt;.env&lt;/code&gt;, add it to &lt;code&gt;.gitignore&lt;/code&gt;. A coding agent runs inside your repo, and that's exactly where a stray key gets committed.&lt;/p&gt;

&lt;p&gt;With this entry selected, the request body was &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;temperature: 0.2&lt;/code&gt;, &lt;code&gt;max_tokens: 4096&lt;/code&gt;, &lt;code&gt;stream&lt;/code&gt; and &lt;code&gt;stream_options&lt;/code&gt;. The 32000 default was gone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Settings that silently stop applying
&lt;/h3&gt;

&lt;p&gt;I also had &lt;code&gt;"model": {"generationConfig": {"samplingParams": {"top_p": 0.5}}}&lt;/code&gt; in the same file. It was never sent. That matches the documented rule: once a &lt;code&gt;modelProviders&lt;/code&gt; entry is selected, its &lt;code&gt;generationConfig&lt;/code&gt; replaces everything, and top-level &lt;code&gt;model.generationConfig&lt;/code&gt; is ignored for that model. &lt;code&gt;samplingParams&lt;/code&gt;, &lt;code&gt;customHeaders&lt;/code&gt; and &lt;code&gt;extra_body&lt;/code&gt; are replaced as whole objects, not merged. If a setting seems to have no effect, check whether it's sitting in the wrong layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What one "Say hi" actually costs
&lt;/h2&gt;

&lt;p&gt;Non-interactive &lt;code&gt;qwen -p "Say hi"&lt;/code&gt; sent two requests, not one.&lt;/p&gt;

&lt;p&gt;The first was the answer. Its system prompt was 30,553 characters, and it carried a second 10,963-character block listing available skills and memory paths, plus six tool definitions (&lt;code&gt;glob&lt;/code&gt;, &lt;code&gt;grep_search&lt;/code&gt;, &lt;code&gt;read_file&lt;/code&gt;, &lt;code&gt;skill&lt;/code&gt;, &lt;code&gt;tool_call&lt;/code&gt;, &lt;code&gt;tool_search&lt;/code&gt;). That's about 41,500 characters before your prompt, which at a rough four characters per token is on the order of 10,000 input tokens.&lt;/p&gt;

&lt;p&gt;The second request came after the answer was printed. Its system prompt began "You are now acting as the managed memory extraction subagent", it replayed the conversation, and it offered &lt;code&gt;write_file&lt;/code&gt; and &lt;code&gt;edit&lt;/code&gt; tools so the model could update memory files under &lt;code&gt;~/.qwen/&lt;/code&gt;. This is the managed auto-memory feature, and it's on by default.&lt;/p&gt;

&lt;p&gt;On a per-token plan, that baseline matters for short prompts. On a plan that counts requests or has a per-minute limit, the memory pass doubles the count for one-shot runs. You can turn it off:&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;"memory"&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;"enableManagedAutoMemory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enableManagedAutoDream"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;With that set, &lt;code&gt;qwen -p "Say hi"&lt;/code&gt; sent exactly one request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retries: two layers, and they multiply
&lt;/h2&gt;

&lt;p&gt;This is the part I'd configure before running Qwen Code in CI or on a slow endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A 429 that clears quickly is handled well.&lt;/strong&gt; When the mock returned 429 with &lt;code&gt;Retry-After: 2&lt;/code&gt; twice, Qwen Code waited about 2 seconds each time and then succeeded on the third request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A server that stays down is a different story.&lt;/strong&gt; With default settings and a mock that always returned 503:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The OpenAI SDK retried each attempt three times with short backoff (about 0.4s, 0.9s, 1.8s), so requests arrived in groups of four.&lt;/li&gt;
&lt;li&gt;Qwen Code's own retry loop repeated those groups with growing gaps (roughly 2, 3, 7, 14, 30 and 30 seconds). Seven groups produced 28 requests in about 107 seconds.&lt;/li&gt;
&lt;li&gt;Then the CLI printed &lt;code&gt;Retrying in 60s (attempt 1/10)&lt;/code&gt; and started a new cycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I stopped it at 200 seconds after 44 requests, still retrying.&lt;/p&gt;

&lt;p&gt;Setting &lt;code&gt;"maxRetries": 0&lt;/code&gt; in &lt;code&gt;generationConfig&lt;/code&gt; removed the SDK layer. The same dead endpoint then got 7 requests over about 74 seconds, and the CLI exited with &lt;code&gt;[API Error: 503 upstream busy]&lt;/code&gt; and code 1. For scripts and CI jobs I'd set &lt;code&gt;maxRetries&lt;/code&gt; to 0 or 1 and wrap the call in your own &lt;code&gt;timeout&lt;/code&gt;, so a provider outage fails the job in a minute instead of hanging it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A guard I was glad to see
&lt;/h2&gt;

&lt;p&gt;My mock had a mode that kept asking for the same tool call with the same arguments. Qwen Code stopped after three requests: &lt;code&gt;Loop detection halted the run (global_tool_call_duplicate: the model repeated the same tool call across the turn...)&lt;/code&gt;. That's an always-on guard, and it's useful with smaller or cheaper models that sometimes get stuck repeating a step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OPENAI_BASE_URL&lt;/code&gt; (or &lt;code&gt;baseUrl&lt;/code&gt;) ends in &lt;code&gt;/v1&lt;/code&gt;, without &lt;code&gt;/chat/completions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;modelProviders&lt;/code&gt; with an &lt;code&gt;envKey&lt;/code&gt;, and keep the key in &lt;code&gt;~/.qwen/.env&lt;/code&gt; or a git-ignored project &lt;code&gt;.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;samplingParams.max_tokens&lt;/code&gt; to your model's real output limit instead of the 32000 default.&lt;/li&gt;
&lt;li&gt;Put every setting for a provider model inside its own &lt;code&gt;generationConfig&lt;/code&gt;; top-level ones are ignored for it.&lt;/li&gt;
&lt;li&gt;Turn off managed auto-memory if you count requests or run one-shot &lt;code&gt;-p&lt;/code&gt; jobs.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;maxRetries&lt;/code&gt; low and use an outer timeout in CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I build &lt;a href="https://apiclaw.biz" rel="noopener noreferrer"&gt;APIClaw&lt;/a&gt;, the OpenAI-compatible gateway in these examples (flat monthly plans; crypto on the site, other payment methods through support). Everything above applies to any compatible endpoint.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>qwen</category>
      <category>cli</category>
      <category>ai</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
