How to Block OpenAI Priority and Flex Tiers per Project
One teammate sets service_tier to priority on a nightly batch job, and your invoice finds out before you do. Since October 21, OpenAI lets you choose in Platform settings which tiers each project may use, so the OpenAI priority tiers (and flex) can be switched off per project instead of policed in code review. By the end you will have tiers restricted at the organization and project level, an agent client that handles the resulting 400 cleanly, and a smoke test that proves it.
1. Decide which tiers each project needs
The project policy covers three tiers: default, flex and priority. The fast tier is evaluated as priority, and the changelog says requests tagged priority automatically use Fast mode, which replaced Priority Processing in July. Block priority and you block Fast too. Scale Tier sits outside this policy.
A starting split, not a rule:
- User-facing agents:
default, pluspriorityonly where latency is worth the price. - Evals, backfills, batch summaries:
flexanddefault. - Experiments and sandboxes:
defaultonly.
Flex is slower, which can quietly break an interactive agent's timeouts. That is a fine reason to block it on the projects that serve people.
2. Restrict OpenAI priority tiers in Platform settings
Organization settings can restrict tiers for every project at once. Each project's own settings then choose from what is left. A project cannot enable a tier the organization has blocked, so set the organization floor first.
OpenAI's error codes guide links to the organization and project settings pages but gives no click-by-click steps, so follow the service tier section on those pages. Before you tighten anything, search your repos for service_tier. Code that still requests a blocked tier will start failing the moment you flip the switch.
3. Name the tier explicitly in your client
Requests that omit service_tier, or send auto, can also fail if they resolve to a disallowed tier. Your code never named a tier, yet it gets the 400. Passing an explicit tier makes every failure attributable to a line you can find.
4. Handle the service_tier 400 error in your agent client
A blocked tier returns HTTP 400 as an invalid_request_error with error.param set to service_tier. The message reads: "Invalid service_tier argument: The requested service tier is not allowed for this project."
Retrying cannot fix it, and the Python SDK agrees: it retries connection errors, 408, 409, 429 and 5xx, not 400. The useful responses are to try another tier you have explicitly allowed, or to fail loudly.
import logging
import openai
from openai import OpenAI
log = logging.getLogger(__name__)
client = OpenAI() # max_retries defaults to 2; the SDK does not retry 400s
# Ordered by preference. List only tiers this project is allowed to use.
TIERS = ['flex', 'default']
class TierBlocked(Exception):
"""Every configured tier is blocked for this project. Fix the settings, not the code."""
def create_response(prompt: str, model: str = '<your-model>'):
for tier in TIERS:
try:
return client.responses.create(model=model, input=prompt, service_tier=tier)
except openai.BadRequestError as exc:
if exc.param != 'service_tier':
raise # a different 400: do not mask it
log.warning('tier %s blocked, request_id=%s', tier, exc.request_id)
raise TierBlocked(f'None of {TIERS} is allowed for this project. Check Platform settings.')
Only a service_tier 400 moves to the next tier. Any other 400 is a real bug in your request and re-raises untouched. If flex stays in your list, raise the client timeout the way OpenAI's flex guide does (timeout=900.0).
Inside an agent loop, raise TierBlocked out of the loop instead of returning it as a tool result. The model cannot change a project setting, and it will happily spend steps trying.
5. Test every tier against each project key
Run this once per project, using that project's API key. It shows exactly what each tier does, including the implicit auto case.
import openai
from openai import OpenAI
client = OpenAI(timeout=900.0) # reads OPENAI_API_KEY: use the key of the project under test
for tier in ['default', 'flex', 'priority', 'auto']:
try:
client.responses.create(
model='<your-model>',
input='ping',
max_output_tokens=16,
service_tier=tier,
)
print(f'{tier:9} allowed')
except openai.BadRequestError as exc:
verdict = 'blocked' if exc.param == 'service_tier' else f'other 400: {exc.message}'
print(f'{tier:9} {verdict}')
Expect blocked for every tier you switched off. Allowed rows make real calls, so the tiny input and 16 output tokens keep the bill small. Wire this into CI for the key you ship with, and a settings change that breaks production fails a test first.
Gotchas
- Implicit tiers fail too. If
defaultis blocked, anautoor omitted tier that resolves to it returns the same 400. - Blocking
priorityblocks Fast. They are evaluated as the same tier. - Check the newer tiers yourself. The error guide names
default,flexandpriorityas the restricted tiers. The changelog also lists anultrafasttier for some models, and the guide does not say whether project settings cover it, so add it to the smoke test. - The organization wins. If a project cannot turn a tier on, look at the organization settings before the project's.
- Alert on
TierBlocked. A spike means a deploy and a settings change disagree.
A tier blocked in Platform settings cannot be bypassed by a stray parameter in a pull request, and a client that fails loudly turns a mysterious 400 in production into a five-minute settings fix.