OpenAI went down for the better part of a day in July 2026 — image generation across ChatGPT and the API was affected for over 13 hours before full recovery. Separate incidents in the same year hit the Realtime API and Codex. If your app calls OpenAI directly with no fallback, every one of those windows was an outage in your product too, whether or not the root cause was your code.
1. OpenAI outages in 2026 weren't rare — multiple multi-hour incidents hit different parts of the API surface across the year.
2. Retry logic alone isn't failover — it just burns time against a provider that isn't coming back yet.
3. A circuit breaker plus a comparable-tier fallback model, both at the proxy layer, is what actually keeps requests succeeding during a real outage.
The Incidents That Make This Concrete
July 2026: An outage affecting image generation across ChatGPT and the API began July 21 and wasn't fully resolved until the following day — well over 13 hours of degraded or unavailable service on that surface.
May-June 2026: Separate tracked incidents hit the Realtime API and SIP/WebRTC flows, plus elevated error rates on newer model versions and Codex engine problems — different failure surfaces, same underlying lesson: no single provider is available 100% of the time, and the parts that fail aren't always the same parts.
None of this is a knock on OpenAI specifically — every major API provider has comparable incident histories. The point isn't "avoid OpenAI," it's "don't build a system where OpenAI's incident becomes your incident by default."
Retry Isn't Failover
The most common half-measure is retry logic with no fallback provider: catch the error, wait, try again, maybe with exponential backoff. This handles transient blips — a single dropped connection, a momentary rate-limit bump — but during an actual outage, every retry hits the same down provider. You're adding latency and load without improving the outcome, and your users are waiting through the full retry budget before the request fails anyway.
The Pattern That Actually Works
1. Circuit breaker on the primary provider
Track the failure rate per provider over a rolling window. Once it crosses a threshold — say, more than 50% of requests failing over the last 30 seconds — trip the breaker and stop sending new requests to that provider for a cooldown period. This is what prevents every request from wasting its retry budget against a provider that's known to be down right now.
2. Failover to a comparable-tier model
When the breaker is open, route to a fallback provider — Claude Sonnet 5 or Gemini 3.5 as a GPT-5-class fallback, not whatever happens to be cheapest. Test this path before you need it. The first time your failover fires in production shouldn't be the first time anyone has seen its output quality.
3. Half-open retry after cooldown
After the cooldown window, let a small percentage of traffic back through to the primary provider to test recovery, rather than an all-or-nothing flip. If those test requests succeed, close the breaker and resume normal routing. If they fail again, stay on the fallback and extend the cooldown.
Want failover across OpenAI, Anthropic, and NVIDIA in one proxy?
Preto proxies to every major provider from a single dashboard — see your cost and health across all of them in one place.
See What Your LLM Spend Looks LikePreto proxies to OpenAI + Anthropic + NVIDIA. One dashboard.
Where This Logic Should Live
Circuit breaking and failover belong at the proxy layer, not scattered across every call site in your application. The proxy sits between your app and every provider — it's the natural place to track per-provider health, make the failover decision once, and keep that logic out of individual feature code. Implementing it per-endpoint means reimplementing the same breaker logic N times and having it drift out of sync as your codebase grows.
A minimal circuit breaker check, conceptually:
class ProviderBreaker:
def __init__(self, failure_threshold=0.5, window_seconds=30, cooldown_seconds=60):
self.failure_threshold = failure_threshold
self.window_seconds = window_seconds
self.cooldown_seconds = cooldown_seconds
self.state = "closed" # closed, open, half_open
self.opened_at = None
def record_result(self, success: bool):
# update rolling failure rate; trip to "open" if threshold exceeded
...
def should_route_to_primary(self):
if self.state == "open":
if time.time() - self.opened_at > self.cooldown_seconds:
self.state = "half_open"
return True # allow a test request through
return False
return True
What This Doesn't Solve
Failover protects against a provider-wide outage. It doesn't protect against a bug in your own prompt logic, a malformed request that fails against every provider identically, or a runaway cost spike from either provider — that's a separate problem, covered by budget enforcement and monitoring, not failover routing. The two are complementary: failover keeps requests succeeding when a provider goes down, budget controls keep costs bounded when something goes wrong on your side.
Frequently Asked Questions
How often does OpenAI's API actually go down?
What's the difference between a retry and a failover?
Do I need a circuit breaker if I already have retry logic?
Will failing over to a different model change my output quality?
See your failover coverage across every provider you use.
Preto proxies to OpenAI, Anthropic, and NVIDIA from one dashboard — cost, latency, and health, all in one place.
See What Your LLM Spend Looks LikeFree forever up to 10K requests. No credit card required.