OpenAI 12-Hour Prompt Caching: When the 2.5x Write Pays Off
Use 12-hour caching for stable prefixes reused across long gaps, keep changing context on 30 minutes or uncached, and reconstruct input charges from usage. Follow a mixed-TTL Responses API example and distinguish API costs from Codex, Work, and Anthropic caching.
Contents

Use OpenAI 12-hour prompt caching for a stable prefix that an agent reuses across long gaps; keep changing session content on 30m or outside cache writes. If the alternative requires a fresh 30m write on every request, one 12h write becomes cheaper on the third total request—the second reuse—provided the prefix still matches. If 30m already keeps hitting, the longer lifetime adds cost without reducing the read price.
What do 30m and 12h cost?
The 12h option buys longer eligibility for cached-input pricing at twice the default cache-write price. OpenAI’s October 20, 2026 API changelog introduced it for Responses; the prompt-caching guide documents the following rules for GPT-5.6 and later, checked as of 2026-10-24.
| Input charge | Multiplier against ordinary input | GPT-6.1 Sol, USD per 1M tokens |
|---|---|---|
| Ordinary input | 1× | $2.00 |
30m write, the default | 1.25× | $2.50 |
12h write | 2.5× | $5.00 |
| Cache read, either lifetime | 0.1× on most models; 0.05× on GPT-6.1 Sol | $0.10 |
These are total write rates. A token billed as a 12h write costs 2.5× ordinary input, rather than ordinary input plus another 2.5×.
The dollar column uses current OpenAI Standard pricing for gpt-6.1-sol, with prompts at or below 272K input tokens and no regional-processing premium. Its output price is $10.00 per 1M tokens. Longer prompts, other service tiers, and regional processing can change rates; use the applicable model pricing conditions before applying the calculations below.
The reusable prefix must contain at least 1,024 visible input tokens. A large request with only a short unchanged opening does not automatically qualify that opening for caching.
When does the higher write price pay off?
Count the writes that longer coverage avoids. Let B be the ordinary input cost of your unchanged prefix, n the total number of requests, r the read multiplier, and k the number of 30m writes, including the first.
Assuming each write or hit covers that whole prefix, with one 12h write followed by successful reads:
12h cost = B × [2.5 + (n - 1) × r]30m cost = B × [1.25 × k + (n - k) × r]No-cache cost = B × n
For both r = 0.1 and r = 0.05, the long-lived cache beats uncached input at n = 3. Against the default cache, it becomes cheaper when k >= 3, while the 12h policy still needs only one write. That means avoiding two subsequent short-lived writes, not merely collecting a large number of hits.
If both policies write once and then hit on every request, 12h remains 1.25 × B more expensive. Frequent interactive conversations therefore have little reason to pay the longer write rate unless they also resume after gaps that cause rewrites.
A gap longer than 30 minutes creates an opportunity for savings, not proof of a miss. OpenAI may retain entries beyond their minimum lifetime, and a 30m read refreshes coverage for at least another 30 minutes. Use observed write counts when forecasting an existing workload.
For a concrete estimate, take a 10,000-token prefix on GPT-6.1 Sol at Standard pricing: B = $0.02 and r = 0.05. Send 12 requests at hours 0 through 11, keeping the prefix unchanged.
| Assumed cache behavior | Prefix input cost across 12 requests |
|---|---|
| No caching: 12 ordinary inputs | $0.240 |
30m: all 12 requests require writes | $0.300 |
12h: one write and 11 reads | $0.061 |
30m: one write and 11 reads | $0.036 |
The two 30m rows show why request spacing alone cannot establish savings. The all-write row is an assumption, not an inevitable hourly result. These estimates exclude changing suffixes, output tokens, and any tool charges; they are not measured invoices.
Why request-wide 12h can cost more
A request-level prompt_cache_options.ttl: "12h" also applies to the implicit breakpoint. With the default mode: "implicit", newly added eligible conversation content can therefore incur a 2.5× write on each turn, even while the older prefix reads cheaply.
For an agent that accumulates tool results and user messages, that growing suffix can overwhelm the savings on the stable opening. A high cache-hit percentage alone does not show whether the policy is economical.
Use one of these arrangements:
- Stable shared material plus reusable session context: set the request default to
30m, with a12hoverride at the end of the shared material. - Stable material plus one-off questions: use
mode: "explicit"and leave the changing question after the final explicit breakpoint. - A conversation whose newest context will be reused soon: retain
mode: "implicit"with the30mrequest default, alongside the shared-prefix12hbreakpoint.
A breakpoint covers the entire prefix before it. For a cold request with a 12h breakpoint at 2,000 tokens and a 30m breakpoint at 5,000, billing assigns 2,000 tokens to long writes and 3,000 to short writes. Put a 12h breakpoint at the later 5,000-token boundary instead, and all 5,000 tokens receive the longer write rate. Each token is billed once at the longest selected write lifetime covering it.
Two lifetime changes also matter. Upgrading valid 30m coverage to 12h incurs a new long write with no credit for the earlier write. A 30m request reading valid 12h coverage pays the read rate without restarting a 12-hour clock or adding a write charge. These overlap and lifetime rules make it worth choosing the intended policy before warming a large prefix.
Configure 12h and 30m in one Responses request
Use a 30m request default and explicit breakpoints to separate shared reference material, session context, and the current question. This example sends directly to OpenAI’s Responses API and prints both generated text and the usage needed for billing checks.
You need Bash, curl, jq, and an OpenAI API key with access to gpt-6.1-sol. In the current directory, prepare:
shared-context.md: useful engineering instructions and reference material reused throughout the day, containing at least 1,024 visible input tokens.session-context.md: the current deployment or pull-request context, which you expect to reuse during this session.
Keep both files unchanged between the two sample calls. When read pauses, paste your API key and press Enter; the terminal will not echo it. Authentication follows the OpenAI API quickstart.
set -o pipefail
read -rs OPENAI_API_KEY && export OPENAI_API_KEY
cache_request() {
jq -n \
--rawfile shared ./shared-context.md \
--rawfile session ./session-context.md \
--arg question "$1" \
'{
model: "gpt-6.1-sol",
service_tier: "default",
reasoning: {effort: "low"},
prompt_cache_options: {mode: "explicit", ttl: "30m"},
input: [
{
role: "developer",
content: [{
type: "input_text",
text: $shared,
prompt_cache_breakpoint: {mode: "explicit", ttl: "12h"}
}]
},
{
role: "user",
content: [
{
type: "input_text",
text: $session,
prompt_cache_breakpoint: {mode: "explicit"}
},
{type: "input_text", text: $question}
]
}
]
}' |
curl --silent --show-error --fail-with-body \
https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- |
jq '{id, status, service_tier,
text: ([.output[]? | .content[]? |
select(.type == "output_text") | .text] | join("\n")),
usage, error}'
}
cache_request "Which deployment risks need review? Answer briefly." &&
cache_request "Which test should run first? Answer briefly."
The first content block overrides the request default with "ttl": "12h". The session block omits its own TTL and inherits "30m". Because the request uses explicit-only mode, the final question has no cache-write charge; it still incurs ordinary input cost.
On a cold, eligible prefix, the first completed response should report long writes in usage.input_tokens_details.cache_write_tokens_details.ttl_12h_tokens. The second should show cached_tokens > 0 and no new long write when the prefix and its coverage remain valid. The returned text contains the usable answer. An immediate repeat checks matching and accounting; assess long-gap savings with requests at your actual production intervals.
If you get 400 invalid_request_error, check the exact TTL strings, the selected model, and the Responses endpoint. If both calls return zero cached tokens, first check the prefix length, then compare the files, model, settings, and breakpoint locations. Changes before the shared breakpoint—including changing tool definitions when you add tools—can prevent reuse.
To test a no-cache baseline, keep mode: "explicit" and remove every prompt_cache_breakpoint. The official request schema documents that explicit mode without markers uses no prompt caching.
Reconstruct the input charge from usage
Treat ordinary input, cache reads, and the two write classes as disjoint buckets. The total cache_write_tokens already contains the ttl_30m_tokens and ttl_12h_tokens components; charging all three would double-count writes. Tokens charged as upgrades to 12h belong to writes and are excluded from cached_tokens.
OpenAI’s usage accounting example has this shape:
{
"usage": {
"input_tokens": 12000,
"input_tokens_details": {
"cached_tokens": 4000,
"cache_write_tokens": 7000,
"cache_write_tokens_details": {
"ttl_30m_tokens": 3000,
"ttl_12h_tokens": 4000
}
}
}
}
Let I be input_tokens, R be cached_tokens, and W30 and W12 be the two TTL-specific write counts. Calculate ordinary input as U = I - R - W30 - W12; here it is 1,000 tokens.
For ordinary input price P in USD per 1M tokens and cached-read multiplier r:
Input cost = P × (U + r × R + 1.25 × W30 + 2.5 × W12) / 1,000,000
The documentation’s hypothetical P = $1, r = 0.1 example gives:
(1000 + 4000 × 0.1 + 3000 × 1.25 + 4000 × 2.5) / 1000000 = $0.01515
For the same usage at GPT-6.1 Sol’s Standard rates, substitute P = $2 and r = 0.05: the input charge is $0.02990. Add output and any other applicable charges separately. This calculation isolates input billing; it does not estimate the full cost of completing a coding task.
Log the response ID, time, model, actual service_tier, and these token counts. If a client omits the TTL breakdown, inspect the raw JSON before calculating mixed-lifetime costs; missing counters are not evidence of zero writes. Aggregate dollar charges across a representative day rather than choosing a policy from one hit percentage.
Finally, 12h specifies a minimum lifetime for cache-read pricing eligibility. It does not set a deletion deadline, change the maximum data-retention policy, or guarantee lower latency on every request.
How does this compare with Codex, Work, and Anthropic?
Keep API billing separate from signed-in product allowances. In his October 21, 2026 post, Tibo Sottiaux described caching for logged-in Codex and Work users as “forever” and said returning to old conversations would hit the cache. That statement concerns those product sessions; it does not define an API TTL or make a subscription unlimited.
The official Codex pricing documentation separately states that Codex credit billing has no separate cache-write charge, while API-key usage follows API pricing. If you run Codex with an API key, budget for the API rules rather than importing a signed-in product promise.
For Claude, the documented choices as of 2026-10-24 are a default 5-minute cache at 1.25× writes and an optional 1-hour cache at 2× writes. Read discounts vary by model: Claude Opus 5.5 and Sonnet 5.5 use 0.05×; other rates appear in Anthropic’s pricing table. Successful reads refresh the lifetime without another write premium, and mixed-TTL requests require longer-lived blocks before shorter-lived ones.
For repeated multi-hour gaps, test OpenAI’s stable-prefix 12h policy first if your application already uses a supported model. For a continuously active session, start with the shorter cache. Comparing providers requires their actual base prices, output usage, and observed cache behavior; lifetime and write multipliers alone cannot establish the cheaper completed task.