Batch and Flex Cost the Same. Why Both Exist?
A pair of service tiers, published as separate tables, with numerically identical prices for every text model that offers both. If your first reaction to that is "so one of them must be redundant," you're not alone — and you're also not quite right, because the redundancy is only in the number, not in what the number is attached to.
The discovery that prompts this question
Anyone who's actually gone through OpenAI's pricing tables row by row, rather than skimming for the number they need, eventually notices it: Batch's input, cached-input, and output prices match Flex's, exactly, model after model. It's not an approximation that happens to look close — it's identical, published as two separate tables that could, in principle, have been one table with two names attached. That's an unusual enough choice that it's worth asking why a vendor would bother.
What actually differs, and why it's not a pricing question
The answer, once you go looking, is that Batch and Flex aren't differentiated on cost at all — they're differentiated on how you make the request and what you're promised in return. Batch takes an uploaded file of requests, commits to completing it within a fixed 24-hour window, and draws from its own separate pool of rate limits. Flex is an ordinary Responses or Chat Completions call with service_tier set to flex: you wait on it like any other request, it can be noticeably slower, and it occasionally fails because capacity isn't available. Same price, different promise about when — and under what resource allocation — your results actually show up.
Why a shared price for different guarantees makes sense
Once you frame it as "same discount, different operational promise," the shared price stops looking redundant and starts looking coherent. Whatever happens inside OpenAI's infrastructure, from the outside both tiers trade speed for price relative to Standard. What's genuinely different is the commitment layered on top: Batch says "submit the whole pile, and it completes within this window, against limits that never touch your live traffic"; Flex says "make a normal call, expect to wait longer, and retry if capacity isn't there." Pricing the underlying compute identically while offering two different commitment levels around it is a reasonable way to let customers choose the guarantee that fits without OpenAI having to price the guarantee itself as a separate line item.
Why two names instead of one tier with an optional flag
An alternative design would fold this into one tier with a boolean "fixed window: yes/no" flag rather than two named tiers. That's plausible, and it's worth asking why OpenAI didn't do it that way. One reasonable guess: naming them separately makes the choice more visible in documentation, pricing pages, and API parameters than a flag buried inside a single tier's configuration would. Whether or not that's the actual internal reasoning, the practical effect for a developer is the same either way — two names to learn instead of one, in exchange for a clearer mental model of what each name promises.
The confusion this design invites, and how to avoid it
Because the prices match, it's genuinely easy to pick between the two arbitrarily, or to inherit whichever one a colleague happened to choose first, without ever actually deciding based on the one thing that differs. That's a real, if minor, failure mode: a job with a genuine deadline that ends up on Flex by habit rather than Batch by decision is exposed to a risk it didn't need to accept, for literally zero savings, since the price was never the differentiator to begin with.
The decision rule this actually reduces to
Once you strip away the pricing question entirely — because there isn't one — the choice between Batch and Flex reduces to the shape of the work. Does it arrive as a pile you can submit at once and collect later, or as individual calls made from inside a running program? A nightly report built from thousands of independent prompts belongs on Batch, for the fixed window and for rate limits that don't compete with your production traffic. An evaluation run or an enrichment step that calls the model inline, and can tolerate slow responses and the occasional retry, fits Flex — with a longer client timeout, which OpenAI's own Flex example sets explicitly. There's no cost argument either way. One practical caveat: Flex is in beta with limited model availability, so confirm your model offers it before designing around it.
Why this is worth its own page rather than a footnote
It would be easy to fold this into a general "service tiers" reference and move on, and this site does cover it there too. It earns a dedicated page because the specific confusion — assuming identical price implies interchangeable product — is exactly the kind of mistake a quick glance at a pricing table produces and a closer read corrects. That gap between a quick glance and a closer read is, in miniature, most of what this whole site exists to close.
A test worth applying to any two "identical" options
Whenever two options in a system are priced identically, it's worth treating that as a prompt to look harder rather than a reason to stop looking — a shared price is either a coincidence (rare, in a deliberately designed pricing system) or a signal that the actual differentiation lives somewhere other than cost. Batch and Flex are a clean example specifically because the differentiator, once you look, is easy to state precisely: one guarantee is fixed, the other isn't. Not every "why do these cost the same" question resolves this cleanly, but the habit of asking it is worth having regardless of the specific answer it turns up.
What this reveals about reading pricing documentation generally
The instinct to stop reading once you've found the number you needed is a reasonable one for most everyday purchasing decisions, where price genuinely is the whole story. It's a worse habit for infrastructure decisions specifically, because infrastructure pricing tables are often structured to communicate operational tradeoffs, not just cost — a service tier's name, its footnotes, and its relationship to sibling tiers frequently carry information a bare number doesn't. Batch and Flex sharing a price is exactly the kind of detail that only becomes informative once you've read past the number to the structure surrounding it.
The takeaway for anyone choosing between the two today
If you've been defaulting to one of these tiers out of habit rather than a considered choice, this is worth revisiting once: does the job actually need Batch's fixed window and separate limits, or would a slower synchronous call have served it just as well? Either answer is fine — the point isn't that one tier is secretly better, it's that the choice should reflect an actual operational need rather than an arbitrary first pick that nobody ever went back and questioned.
Verified 2026-10-28 against CodexHow facts module (src/data/facts/) — see /about/#accuracy.