From 36820e69ba6cf1dc3f8d411e48a36e56084fbbc4 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 22 Jul 2026 20:45:29 +0000
Subject: [PATCH 1/3] feat(api): accept `None` for
prompt_cache_key/safety_identifier
---
.stats.yml | 4 +-
.../resources/beta/responses/responses.py | 40 +++++------
.../resources/chat/completions/completions.py | 66 ++++++++++---------
src/openai/resources/responses/responses.py | 64 +++++++++---------
src/openai/types/beta/beta_response.py | 5 +-
src/openai/types/beta/beta_response_error.py | 1 +
.../types/beta/beta_response_text_config.py | 2 +-
.../beta/beta_response_text_config_param.py | 2 +-
.../types/beta/beta_responses_client_event.py | 5 +-
.../beta/beta_responses_client_event_param.py | 9 ++-
.../types/beta/response_create_params.py | 9 ++-
.../responses/input_token_count_params.py | 7 +-
.../types/chat/completion_create_params.py | 6 +-
.../responses/input_token_count_params.py | 2 +-
.../types/responses/response_create_params.py | 4 +-
src/openai/types/responses/response_error.py | 1 +
.../types/responses/response_text_config.py | 2 +-
.../responses/response_text_config_param.py | 2 +-
.../responses/responses_client_event_param.py | 4 +-
src/openai/types/shared/reasoning.py | 5 +-
src/openai/types/shared_params/reasoning.py | 5 +-
21 files changed, 137 insertions(+), 108 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 7f13b9ff35..39bf33e59e 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 272
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-8ed7dcb0d163e7f5205dbe172d6ad5b7ce367b23c20629830e39a0aee920a029.yml
-openapi_spec_hash: 011cdae0c67909fb80a4a5eb54ca5bca
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5555d8e0f800f68d951749454d94fa8b899fc3722550657578b1d8a9fd3322e8.yml
+openapi_spec_hash: 754a2e573085f55d60f02dbc3a5ef2b1
config_hash: 896f0f71bc7d1ee09435813cdef97523
diff --git a/src/openai/resources/beta/responses/responses.py b/src/openai/resources/beta/responses/responses.py
index 4ec4723d20..ed244635d1 100644
--- a/src/openai/resources/beta/responses/responses.py
+++ b/src/openai/resources/beta/responses/responses.py
@@ -222,11 +222,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Omit = omit,
@@ -604,11 +604,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -985,11 +985,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -1364,11 +1364,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Literal[True] | Omit = omit,
@@ -2104,11 +2104,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Omit = omit,
@@ -2486,11 +2486,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -2867,11 +2867,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -3246,11 +3246,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[response_create_params.Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Literal[True] | Omit = omit,
@@ -4990,11 +4990,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: beta_responses_client_event_param.ResponseCreatePromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[beta_responses_client_event_param.ResponseCreateReasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[bool] | Omit = omit,
@@ -5193,11 +5193,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[BetaResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: beta_responses_client_event_param.ResponseCreatePromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[beta_responses_client_event_param.ResponseCreateReasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[bool] | Omit = omit,
diff --git a/src/openai/resources/chat/completions/completions.py b/src/openai/resources/chat/completions/completions.py
index f8e7d40772..8d75855e3a 100644
--- a/src/openai/resources/chat/completions/completions.py
+++ b/src/openai/resources/chat/completions/completions.py
@@ -109,11 +109,11 @@ def parse(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -269,12 +269,12 @@ def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -559,7 +559,8 @@ def create(
verbosity: Constrains the verbosity of the model's response. Lower values will result in
more concise responses, while higher values will result in more verbose
- responses. Currently supported values are `low`, `medium`, and `high`.
+ responses. Currently supported values are `low`, `medium`, and `high`. The
+ default is `medium`.
web_search_options: This tool searches the web for relevant results to use in a response. Learn more
about the
@@ -597,12 +598,12 @@ def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -886,7 +887,8 @@ def create(
verbosity: Constrains the verbosity of the model's response. Lower values will result in
more concise responses, while higher values will result in more verbose
- responses. Currently supported values are `low`, `medium`, and `high`.
+ responses. Currently supported values are `low`, `medium`, and `high`. The
+ default is `medium`.
web_search_options: This tool searches the web for relevant results to use in a response. Learn more
about the
@@ -924,12 +926,12 @@ def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -1213,7 +1215,8 @@ def create(
verbosity: Constrains the verbosity of the model's response. Lower values will result in
more concise responses, while higher values will result in more verbose
- responses. Currently supported values are `low`, `medium`, and `high`.
+ responses. Currently supported values are `low`, `medium`, and `high`. The
+ default is `medium`.
web_search_options: This tool searches the web for relevant results to use in a response. Learn more
about the
@@ -1250,12 +1253,12 @@ def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -1550,11 +1553,11 @@ def stream(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -1705,11 +1708,11 @@ async def parse(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -1865,12 +1868,12 @@ async def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -2155,7 +2158,8 @@ async def create(
verbosity: Constrains the verbosity of the model's response. Lower values will result in
more concise responses, while higher values will result in more verbose
- responses. Currently supported values are `low`, `medium`, and `high`.
+ responses. Currently supported values are `low`, `medium`, and `high`. The
+ default is `medium`.
web_search_options: This tool searches the web for relevant results to use in a response. Learn more
about the
@@ -2193,12 +2197,12 @@ async def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -2482,7 +2486,8 @@ async def create(
verbosity: Constrains the verbosity of the model's response. Lower values will result in
more concise responses, while higher values will result in more verbose
- responses. Currently supported values are `low`, `medium`, and `high`.
+ responses. Currently supported values are `low`, `medium`, and `high`. The
+ default is `medium`.
web_search_options: This tool searches the web for relevant results to use in a response. Learn more
about the
@@ -2520,12 +2525,12 @@ async def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -2809,7 +2814,8 @@ async def create(
verbosity: Constrains the verbosity of the model's response. Lower values will result in
more concise responses, while higher values will result in more verbose
- responses. Currently supported values are `low`, `medium`, and `high`.
+ responses. Currently supported values are `low`, `medium`, and `high`. The
+ default is `medium`.
web_search_options: This tool searches the web for relevant results to use in a response. Learn more
about the
@@ -2846,12 +2852,12 @@ async def create(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
response_format: completion_create_params.ResponseFormat | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
@@ -3146,11 +3152,11 @@ def stream(
parallel_tool_calls: bool | Omit = omit,
prediction: Optional[ChatCompletionPredictionContentParam] | Omit = omit,
presence_penalty: Optional[float] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: completion_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning_effort: Optional[ReasoningEffort] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
seed: Optional[int] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
stop: Union[Optional[str], SequenceNotStr[str], None] | Omit = omit,
diff --git a/src/openai/resources/responses/responses.py b/src/openai/resources/responses/responses.py
index 4fcf33a257..54ce5ee26c 100644
--- a/src/openai/resources/responses/responses.py
+++ b/src/openai/resources/responses/responses.py
@@ -147,11 +147,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Omit = omit,
@@ -425,11 +425,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -702,11 +702,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -977,11 +977,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Literal[True] | Omit = omit,
@@ -1088,11 +1088,11 @@ def stream(
moderation: Optional[response_create_params.Moderation] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -1131,11 +1131,11 @@ def stream(
moderation: Optional[response_create_params.Moderation] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -1293,11 +1293,11 @@ def parse(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Literal[True] | Omit = omit,
@@ -1970,11 +1970,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Omit = omit,
@@ -2248,11 +2248,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -2525,11 +2525,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -2800,11 +2800,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Literal[True] | Omit = omit,
@@ -2911,11 +2911,11 @@ def stream(
moderation: Optional[response_create_params.Moderation] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -2954,11 +2954,11 @@ def stream(
moderation: Optional[response_create_params.Moderation] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream_options: Optional[response_create_params.StreamOptions] | Omit = omit,
@@ -3115,11 +3115,11 @@ async def parse(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: response_create_params.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[Literal[False]] | Literal[True] | Omit = omit,
@@ -4831,11 +4831,11 @@ def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: responses_client_event_param.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[bool] | Omit = omit,
@@ -4915,11 +4915,11 @@ async def create(
parallel_tool_calls: Optional[bool] | Omit = omit,
previous_response_id: Optional[str] | Omit = omit,
prompt: Optional[ResponsePromptParam] | Omit = omit,
- prompt_cache_key: str | Omit = omit,
+ prompt_cache_key: Optional[str] | Omit = omit,
prompt_cache_options: responses_client_event_param.PromptCacheOptions | Omit = omit,
prompt_cache_retention: Optional[Literal["in_memory", "24h"]] | Omit = omit,
reasoning: Optional[Reasoning] | Omit = omit,
- safety_identifier: str | Omit = omit,
+ safety_identifier: Optional[str] | Omit = omit,
service_tier: Optional[Literal["auto", "default", "flex", "scale", "priority"]] | Omit = omit,
store: Optional[bool] | Omit = omit,
stream: Optional[bool] | Omit = omit,
diff --git a/src/openai/types/beta/beta_response.py b/src/openai/types/beta/beta_response.py
index eb50bcbcd0..f9bea6200b 100644
--- a/src/openai/types/beta/beta_response.py
+++ b/src/openai/types/beta/beta_response.py
@@ -201,7 +201,10 @@ class Reasoning(BaseModel):
context: Optional[Literal["auto", "current_turn", "all_turns"]] = None
"""
- Controls which reasoning items are rendered back to the model on later turns.
+ Controls which reasoning items are rendered back to the model on later turns. If
+ omitted or set to `auto`, the model determines the context mode. The `gpt-5.6`
+ model family defaults to `all_turns`; earlier models default to `current_turn`.
+
When returned on a response, this is the effective reasoning context mode used
for the response.
"""
diff --git a/src/openai/types/beta/beta_response_error.py b/src/openai/types/beta/beta_response_error.py
index c725765d63..0d423fa1fa 100644
--- a/src/openai/types/beta/beta_response_error.py
+++ b/src/openai/types/beta/beta_response_error.py
@@ -14,6 +14,7 @@ class BetaResponseError(BaseModel):
"server_error",
"rate_limit_exceeded",
"invalid_prompt",
+ "data_residency_mismatch",
"bio_policy",
"vector_store_timeout",
"invalid_image",
diff --git a/src/openai/types/beta/beta_response_text_config.py b/src/openai/types/beta/beta_response_text_config.py
index a0ec4e66d9..b3e4d25798 100644
--- a/src/openai/types/beta/beta_response_text_config.py
+++ b/src/openai/types/beta/beta_response_text_config.py
@@ -39,5 +39,5 @@ class BetaResponseTextConfig(BaseModel):
Lower values will result in more concise responses, while higher values will
result in more verbose responses. Currently supported values are `low`,
- `medium`, and `high`.
+ `medium`, and `high`. The default is `medium`.
"""
diff --git a/src/openai/types/beta/beta_response_text_config_param.py b/src/openai/types/beta/beta_response_text_config_param.py
index 52f2cd6a1a..eb17df7ad9 100644
--- a/src/openai/types/beta/beta_response_text_config_param.py
+++ b/src/openai/types/beta/beta_response_text_config_param.py
@@ -40,5 +40,5 @@ class BetaResponseTextConfigParam(TypedDict, total=False):
Lower values will result in more concise responses, while higher values will
result in more verbose responses. Currently supported values are `low`,
- `medium`, and `high`.
+ `medium`, and `high`. The default is `medium`.
"""
diff --git a/src/openai/types/beta/beta_responses_client_event.py b/src/openai/types/beta/beta_responses_client_event.py
index 6450d15260..a83f7038b2 100644
--- a/src/openai/types/beta/beta_responses_client_event.py
+++ b/src/openai/types/beta/beta_responses_client_event.py
@@ -135,7 +135,10 @@ class ResponseCreateReasoning(BaseModel):
context: Optional[Literal["auto", "current_turn", "all_turns"]] = None
"""
- Controls which reasoning items are rendered back to the model on later turns.
+ Controls which reasoning items are rendered back to the model on later turns. If
+ omitted or set to `auto`, the model determines the context mode. The `gpt-5.6`
+ model family defaults to `all_turns`; earlier models default to `current_turn`.
+
When returned on a response, this is the effective reasoning context mode used
for the response.
"""
diff --git a/src/openai/types/beta/beta_responses_client_event_param.py b/src/openai/types/beta/beta_responses_client_event_param.py
index adc3e958ac..e5d84f2b4e 100644
--- a/src/openai/types/beta/beta_responses_client_event_param.py
+++ b/src/openai/types/beta/beta_responses_client_event_param.py
@@ -135,7 +135,10 @@ class ResponseCreateReasoning(TypedDict, total=False):
context: Optional[Literal["auto", "current_turn", "all_turns"]]
"""
- Controls which reasoning items are rendered back to the model on later turns.
+ Controls which reasoning items are rendered back to the model on later turns. If
+ omitted or set to `auto`, the model determines the context mode. The `gpt-5.6`
+ model family defaults to `all_turns`; earlier models default to `current_turn`.
+
When returned on a response, this is the effective reasoning context mode used
for the response.
"""
@@ -437,7 +440,7 @@ class ResponseCreate(TypedDict, total=False):
[Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
"""
- prompt_cache_key: str
+ prompt_cache_key: Optional[str]
"""
Used by OpenAI to cache responses for similar requests to optimize your cache
hit rates. Replaces the `user` field.
@@ -485,7 +488,7 @@ class ResponseCreate(TypedDict, total=False):
[reasoning models](https://platform.openai.com/docs/guides/reasoning).
"""
- safety_identifier: str
+ safety_identifier: Optional[str]
"""
A stable identifier used to help detect users of your application that may be
violating OpenAI's usage policies. The IDs should be a string that uniquely
diff --git a/src/openai/types/beta/response_create_params.py b/src/openai/types/beta/response_create_params.py
index 35694e319a..c86103cded 100644
--- a/src/openai/types/beta/response_create_params.py
+++ b/src/openai/types/beta/response_create_params.py
@@ -256,7 +256,7 @@ class ResponseCreateParamsBase(TypedDict, total=False):
[Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
"""
- prompt_cache_key: str
+ prompt_cache_key: Optional[str]
"""
Used by OpenAI to cache responses for similar requests to optimize your cache
hit rates. Replaces the `user` field.
@@ -304,7 +304,7 @@ class ResponseCreateParamsBase(TypedDict, total=False):
[reasoning models](https://platform.openai.com/docs/guides/reasoning).
"""
- safety_identifier: str
+ safety_identifier: Optional[str]
"""
A stable identifier used to help detect users of your application that may be
violating OpenAI's usage policies. The IDs should be a string that uniquely
@@ -520,7 +520,10 @@ class Reasoning(TypedDict, total=False):
context: Optional[Literal["auto", "current_turn", "all_turns"]]
"""
- Controls which reasoning items are rendered back to the model on later turns.
+ Controls which reasoning items are rendered back to the model on later turns. If
+ omitted or set to `auto`, the model determines the context mode. The `gpt-5.6`
+ model family defaults to `all_turns`; earlier models default to `current_turn`.
+
When returned on a response, this is the effective reasoning context mode used
for the response.
"""
diff --git a/src/openai/types/beta/responses/input_token_count_params.py b/src/openai/types/beta/responses/input_token_count_params.py
index 0d3c91e86d..46413246b4 100644
--- a/src/openai/types/beta/responses/input_token_count_params.py
+++ b/src/openai/types/beta/responses/input_token_count_params.py
@@ -123,7 +123,10 @@ class Reasoning(TypedDict, total=False):
context: Optional[Literal["auto", "current_turn", "all_turns"]]
"""
- Controls which reasoning items are rendered back to the model on later turns.
+ Controls which reasoning items are rendered back to the model on later turns. If
+ omitted or set to `auto`, the model determines the context mode. The `gpt-5.6`
+ model family defaults to `all_turns`; earlier models default to `current_turn`.
+
When returned on a response, this is the effective reasoning context mode used
for the response.
"""
@@ -194,7 +197,7 @@ class Text(TypedDict, total=False):
Lower values will result in more concise responses, while higher values will
result in more verbose responses. Currently supported values are `low`,
- `medium`, and `high`.
+ `medium`, and `high`. The default is `medium`.
"""
diff --git a/src/openai/types/chat/completion_create_params.py b/src/openai/types/chat/completion_create_params.py
index dfccdb0574..ce027e067a 100644
--- a/src/openai/types/chat/completion_create_params.py
+++ b/src/openai/types/chat/completion_create_params.py
@@ -186,7 +186,7 @@ class CompletionCreateParamsBase(TypedDict, total=False):
far, increasing the model's likelihood to talk about new topics.
"""
- prompt_cache_key: str
+ prompt_cache_key: Optional[str]
"""
Used by OpenAI to cache responses for similar requests to optimize your cache
hit rates. Replaces the `user` field.
@@ -251,7 +251,7 @@ class CompletionCreateParamsBase(TypedDict, total=False):
preferred for models that support it.
"""
- safety_identifier: str
+ safety_identifier: Optional[str]
"""
A stable identifier used to help detect users of your application that may be
violating OpenAI's usage policies. The IDs should be a string that uniquely
@@ -368,7 +368,7 @@ class CompletionCreateParamsBase(TypedDict, total=False):
Lower values will result in more concise responses, while higher values will
result in more verbose responses. Currently supported values are `low`,
- `medium`, and `high`.
+ `medium`, and `high`. The default is `medium`.
"""
web_search_options: WebSearchOptions
diff --git a/src/openai/types/responses/input_token_count_params.py b/src/openai/types/responses/input_token_count_params.py
index 78ed01f432..17c350d5ac 100644
--- a/src/openai/types/responses/input_token_count_params.py
+++ b/src/openai/types/responses/input_token_count_params.py
@@ -143,7 +143,7 @@ class Text(TypedDict, total=False):
Lower values will result in more concise responses, while higher values will
result in more verbose responses. Currently supported values are `low`,
- `medium`, and `high`.
+ `medium`, and `high`. The default is `medium`.
"""
diff --git a/src/openai/types/responses/response_create_params.py b/src/openai/types/responses/response_create_params.py
index f775970eff..76d3b5fde6 100644
--- a/src/openai/types/responses/response_create_params.py
+++ b/src/openai/types/responses/response_create_params.py
@@ -154,7 +154,7 @@ class ResponseCreateParamsBase(TypedDict, total=False):
[Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
"""
- prompt_cache_key: str
+ prompt_cache_key: Optional[str]
"""
Used by OpenAI to cache responses for similar requests to optimize your cache
hit rates. Replaces the `user` field.
@@ -202,7 +202,7 @@ class ResponseCreateParamsBase(TypedDict, total=False):
[reasoning models](https://platform.openai.com/docs/guides/reasoning).
"""
- safety_identifier: str
+ safety_identifier: Optional[str]
"""
A stable identifier used to help detect users of your application that may be
violating OpenAI's usage policies. The IDs should be a string that uniquely
diff --git a/src/openai/types/responses/response_error.py b/src/openai/types/responses/response_error.py
index b38a9bada8..254a7e3770 100644
--- a/src/openai/types/responses/response_error.py
+++ b/src/openai/types/responses/response_error.py
@@ -14,6 +14,7 @@ class ResponseError(BaseModel):
"server_error",
"rate_limit_exceeded",
"invalid_prompt",
+ "data_residency_mismatch",
"bio_policy",
"vector_store_timeout",
"invalid_image",
diff --git a/src/openai/types/responses/response_text_config.py b/src/openai/types/responses/response_text_config.py
index fbf4da0b03..2095c10a1d 100644
--- a/src/openai/types/responses/response_text_config.py
+++ b/src/openai/types/responses/response_text_config.py
@@ -39,5 +39,5 @@ class ResponseTextConfig(BaseModel):
Lower values will result in more concise responses, while higher values will
result in more verbose responses. Currently supported values are `low`,
- `medium`, and `high`.
+ `medium`, and `high`. The default is `medium`.
"""
diff --git a/src/openai/types/responses/response_text_config_param.py b/src/openai/types/responses/response_text_config_param.py
index 9cd54765b0..fadb424bb1 100644
--- a/src/openai/types/responses/response_text_config_param.py
+++ b/src/openai/types/responses/response_text_config_param.py
@@ -40,5 +40,5 @@ class ResponseTextConfigParam(TypedDict, total=False):
Lower values will result in more concise responses, while higher values will
result in more verbose responses. Currently supported values are `low`,
- `medium`, and `high`.
+ `medium`, and `high`. The default is `medium`.
"""
diff --git a/src/openai/types/responses/responses_client_event_param.py b/src/openai/types/responses/responses_client_event_param.py
index 818248b818..4d7981d2df 100644
--- a/src/openai/types/responses/responses_client_event_param.py
+++ b/src/openai/types/responses/responses_client_event_param.py
@@ -258,7 +258,7 @@ class ResponsesClientEventParam(TypedDict, total=False):
[Learn more](https://platform.openai.com/docs/guides/text?api-mode=responses#reusable-prompts).
"""
- prompt_cache_key: str
+ prompt_cache_key: Optional[str]
"""
Used by OpenAI to cache responses for similar requests to optimize your cache
hit rates. Replaces the `user` field.
@@ -306,7 +306,7 @@ class ResponsesClientEventParam(TypedDict, total=False):
[reasoning models](https://platform.openai.com/docs/guides/reasoning).
"""
- safety_identifier: str
+ safety_identifier: Optional[str]
"""
A stable identifier used to help detect users of your application that may be
violating OpenAI's usage policies. The IDs should be a string that uniquely
diff --git a/src/openai/types/shared/reasoning.py b/src/openai/types/shared/reasoning.py
index 7dddbb9b44..c1fe873ae0 100644
--- a/src/openai/types/shared/reasoning.py
+++ b/src/openai/types/shared/reasoning.py
@@ -18,7 +18,10 @@ class Reasoning(BaseModel):
context: Optional[Literal["auto", "current_turn", "all_turns"]] = None
"""
- Controls which reasoning items are rendered back to the model on later turns.
+ Controls which reasoning items are rendered back to the model on later turns. If
+ omitted or set to `auto`, the model determines the context mode. The `gpt-5.6`
+ model family defaults to `all_turns`; earlier models default to `current_turn`.
+
When returned on a response, this is the effective reasoning context mode used
for the response.
"""
diff --git a/src/openai/types/shared_params/reasoning.py b/src/openai/types/shared_params/reasoning.py
index 70cf624f0e..3dd3fdf5f1 100644
--- a/src/openai/types/shared_params/reasoning.py
+++ b/src/openai/types/shared_params/reasoning.py
@@ -19,7 +19,10 @@ class Reasoning(TypedDict, total=False):
context: Optional[Literal["auto", "current_turn", "all_turns"]]
"""
- Controls which reasoning items are rendered back to the model on later turns.
+ Controls which reasoning items are rendered back to the model on later turns. If
+ omitted or set to `auto`, the model determines the context mode. The `gpt-5.6`
+ model family defaults to `all_turns`; earlier models default to `current_turn`.
+
When returned on a response, this is the effective reasoning context mode used
for the response.
"""
From 1ff13afb6e831394036686a1c352bbec6d704c68 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 23 Jul 2026 16:15:58 +0000
Subject: [PATCH 2/3] feat(api): add support for `spend_limit` admin apis
---
.stats.yml | 8 +-
api.md | 28 ++
.../resources/admin/organization/__init__.py | 14 +
.../admin/organization/organization.py | 32 ++
.../admin/organization/projects/__init__.py | 14 +
.../admin/organization/projects/projects.py | 32 ++
.../organization/projects/spend_limit.py | 380 ++++++++++++++++++
.../admin/organization/spend_limit.py | 318 +++++++++++++++
.../types/admin/organization/__init__.py | 3 +
.../organization/organization_spend_limit.py | 37 ++
.../organization_spend_limit_deleted.py | 17 +
.../admin/organization/projects/__init__.py | 3 +
.../projects/project_spend_limit.py | 37 ++
.../projects/project_spend_limit_deleted.py | 17 +
.../projects/spend_limit_update_params.py | 21 +
.../organization/spend_limit_update_params.py | 21 +
.../organization/projects/test_spend_limit.py | 279 +++++++++++++
.../admin/organization/test_spend_limit.py | 201 +++++++++
18 files changed, 1458 insertions(+), 4 deletions(-)
create mode 100644 src/openai/resources/admin/organization/projects/spend_limit.py
create mode 100644 src/openai/resources/admin/organization/spend_limit.py
create mode 100644 src/openai/types/admin/organization/organization_spend_limit.py
create mode 100644 src/openai/types/admin/organization/organization_spend_limit_deleted.py
create mode 100644 src/openai/types/admin/organization/projects/project_spend_limit.py
create mode 100644 src/openai/types/admin/organization/projects/project_spend_limit_deleted.py
create mode 100644 src/openai/types/admin/organization/projects/spend_limit_update_params.py
create mode 100644 src/openai/types/admin/organization/spend_limit_update_params.py
create mode 100644 tests/api_resources/admin/organization/projects/test_spend_limit.py
create mode 100644 tests/api_resources/admin/organization/test_spend_limit.py
diff --git a/.stats.yml b/.stats.yml
index 39bf33e59e..61025cba01 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 272
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-5555d8e0f800f68d951749454d94fa8b899fc3722550657578b1d8a9fd3322e8.yml
-openapi_spec_hash: 754a2e573085f55d60f02dbc3a5ef2b1
-config_hash: 896f0f71bc7d1ee09435813cdef97523
+configured_endpoints: 278
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai/openai-0650ebae454b4200491980d7663cb7ceabcff90dcb3ed9f67c3bca3e861a2bf6.yml
+openapi_spec_hash: e9576bced964246b7e685a5ad30afffa
+config_hash: 43e311595bcc4fb6b32eba0684de48d8
diff --git a/api.md b/api.md
index 8ee735e5df..0124bff7d0 100644
--- a/api.md
+++ b/api.md
@@ -1102,6 +1102,20 @@ Methods:
- client.admin.organization.data_retention.retrieve() -> OrganizationDataRetention
- client.admin.organization.data_retention.update(\*\*params) -> OrganizationDataRetention
+### SpendLimit
+
+Types:
+
+```python
+from openai.types.admin.organization import OrganizationSpendLimit, OrganizationSpendLimitDeleted
+```
+
+Methods:
+
+- client.admin.organization.spend_limit.retrieve() -> OrganizationSpendLimit
+- client.admin.organization.spend_limit.update(\*\*params) -> OrganizationSpendLimit
+- client.admin.organization.spend_limit.delete() -> OrganizationSpendLimitDeleted
+
### SpendAlerts
Types:
@@ -1347,6 +1361,20 @@ Methods:
- client.admin.organization.projects.data_retention.retrieve(project_id) -> ProjectDataRetention
- client.admin.organization.projects.data_retention.update(project_id, \*\*params) -> ProjectDataRetention
+#### SpendLimit
+
+Types:
+
+```python
+from openai.types.admin.organization.projects import ProjectSpendLimit, ProjectSpendLimitDeleted
+```
+
+Methods:
+
+- client.admin.organization.projects.spend_limit.retrieve(project_id) -> ProjectSpendLimit
+- client.admin.organization.projects.spend_limit.update(project_id, \*\*params) -> ProjectSpendLimit
+- client.admin.organization.projects.spend_limit.delete(project_id) -> ProjectSpendLimitDeleted
+
#### SpendAlerts
Types:
diff --git a/src/openai/resources/admin/organization/__init__.py b/src/openai/resources/admin/organization/__init__.py
index d87fbbc81d..cb306466ea 100644
--- a/src/openai/resources/admin/organization/__init__.py
+++ b/src/openai/resources/admin/organization/__init__.py
@@ -56,6 +56,14 @@
AuditLogsWithStreamingResponse,
AsyncAuditLogsWithStreamingResponse,
)
+from .spend_limit import (
+ SpendLimit,
+ AsyncSpendLimit,
+ SpendLimitWithRawResponse,
+ AsyncSpendLimitWithRawResponse,
+ SpendLimitWithStreamingResponse,
+ AsyncSpendLimitWithStreamingResponse,
+)
from .certificates import (
Certificates,
AsyncCertificates,
@@ -146,6 +154,12 @@
"AsyncDataRetentionWithRawResponse",
"DataRetentionWithStreamingResponse",
"AsyncDataRetentionWithStreamingResponse",
+ "SpendLimit",
+ "AsyncSpendLimit",
+ "SpendLimitWithRawResponse",
+ "AsyncSpendLimitWithRawResponse",
+ "SpendLimitWithStreamingResponse",
+ "AsyncSpendLimitWithStreamingResponse",
"SpendAlerts",
"AsyncSpendAlerts",
"SpendAlertsWithRawResponse",
diff --git a/src/openai/resources/admin/organization/organization.py b/src/openai/resources/admin/organization/organization.py
index 62bba207cb..7100cbcbfb 100644
--- a/src/openai/resources/admin/organization/organization.py
+++ b/src/openai/resources/admin/organization/organization.py
@@ -35,6 +35,14 @@
AuditLogsWithStreamingResponse,
AsyncAuditLogsWithStreamingResponse,
)
+from .spend_limit import (
+ SpendLimit,
+ AsyncSpendLimit,
+ SpendLimitWithRawResponse,
+ AsyncSpendLimitWithRawResponse,
+ SpendLimitWithStreamingResponse,
+ AsyncSpendLimitWithStreamingResponse,
+)
from .users.users import (
Users,
AsyncUsers,
@@ -130,6 +138,10 @@ def roles(self) -> Roles:
def data_retention(self) -> DataRetention:
return DataRetention(self._client)
+ @cached_property
+ def spend_limit(self) -> SpendLimit:
+ return SpendLimit(self._client)
+
@cached_property
def spend_alerts(self) -> SpendAlerts:
return SpendAlerts(self._client)
@@ -196,6 +208,10 @@ def roles(self) -> AsyncRoles:
def data_retention(self) -> AsyncDataRetention:
return AsyncDataRetention(self._client)
+ @cached_property
+ def spend_limit(self) -> AsyncSpendLimit:
+ return AsyncSpendLimit(self._client)
+
@cached_property
def spend_alerts(self) -> AsyncSpendAlerts:
return AsyncSpendAlerts(self._client)
@@ -265,6 +281,10 @@ def roles(self) -> RolesWithRawResponse:
def data_retention(self) -> DataRetentionWithRawResponse:
return DataRetentionWithRawResponse(self._organization.data_retention)
+ @cached_property
+ def spend_limit(self) -> SpendLimitWithRawResponse:
+ return SpendLimitWithRawResponse(self._organization.spend_limit)
+
@cached_property
def spend_alerts(self) -> SpendAlertsWithRawResponse:
return SpendAlertsWithRawResponse(self._organization.spend_alerts)
@@ -315,6 +335,10 @@ def roles(self) -> AsyncRolesWithRawResponse:
def data_retention(self) -> AsyncDataRetentionWithRawResponse:
return AsyncDataRetentionWithRawResponse(self._organization.data_retention)
+ @cached_property
+ def spend_limit(self) -> AsyncSpendLimitWithRawResponse:
+ return AsyncSpendLimitWithRawResponse(self._organization.spend_limit)
+
@cached_property
def spend_alerts(self) -> AsyncSpendAlertsWithRawResponse:
return AsyncSpendAlertsWithRawResponse(self._organization.spend_alerts)
@@ -365,6 +389,10 @@ def roles(self) -> RolesWithStreamingResponse:
def data_retention(self) -> DataRetentionWithStreamingResponse:
return DataRetentionWithStreamingResponse(self._organization.data_retention)
+ @cached_property
+ def spend_limit(self) -> SpendLimitWithStreamingResponse:
+ return SpendLimitWithStreamingResponse(self._organization.spend_limit)
+
@cached_property
def spend_alerts(self) -> SpendAlertsWithStreamingResponse:
return SpendAlertsWithStreamingResponse(self._organization.spend_alerts)
@@ -415,6 +443,10 @@ def roles(self) -> AsyncRolesWithStreamingResponse:
def data_retention(self) -> AsyncDataRetentionWithStreamingResponse:
return AsyncDataRetentionWithStreamingResponse(self._organization.data_retention)
+ @cached_property
+ def spend_limit(self) -> AsyncSpendLimitWithStreamingResponse:
+ return AsyncSpendLimitWithStreamingResponse(self._organization.spend_limit)
+
@cached_property
def spend_alerts(self) -> AsyncSpendAlertsWithStreamingResponse:
return AsyncSpendAlertsWithStreamingResponse(self._organization.spend_alerts)
diff --git a/src/openai/resources/admin/organization/projects/__init__.py b/src/openai/resources/admin/organization/projects/__init__.py
index 3bc97170fd..f585c0eabb 100644
--- a/src/openai/resources/admin/organization/projects/__init__.py
+++ b/src/openai/resources/admin/organization/projects/__init__.py
@@ -48,6 +48,14 @@
RateLimitsWithStreamingResponse,
AsyncRateLimitsWithStreamingResponse,
)
+from .spend_limit import (
+ SpendLimit,
+ AsyncSpendLimit,
+ SpendLimitWithRawResponse,
+ AsyncSpendLimitWithRawResponse,
+ SpendLimitWithStreamingResponse,
+ AsyncSpendLimitWithStreamingResponse,
+)
from .certificates import (
Certificates,
AsyncCertificates,
@@ -152,6 +160,12 @@
"AsyncDataRetentionWithRawResponse",
"DataRetentionWithStreamingResponse",
"AsyncDataRetentionWithStreamingResponse",
+ "SpendLimit",
+ "AsyncSpendLimit",
+ "SpendLimitWithRawResponse",
+ "AsyncSpendLimitWithRawResponse",
+ "SpendLimitWithStreamingResponse",
+ "AsyncSpendLimitWithStreamingResponse",
"SpendAlerts",
"AsyncSpendAlerts",
"SpendAlertsWithRawResponse",
diff --git a/src/openai/resources/admin/organization/projects/projects.py b/src/openai/resources/admin/organization/projects/projects.py
index ea2172b594..36d8b0805a 100644
--- a/src/openai/resources/admin/organization/projects/projects.py
+++ b/src/openai/resources/admin/organization/projects/projects.py
@@ -34,6 +34,14 @@
RateLimitsWithStreamingResponse,
AsyncRateLimitsWithStreamingResponse,
)
+from .spend_limit import (
+ SpendLimit,
+ AsyncSpendLimit,
+ SpendLimitWithRawResponse,
+ AsyncSpendLimitWithRawResponse,
+ SpendLimitWithStreamingResponse,
+ AsyncSpendLimitWithStreamingResponse,
+)
from .users.users import (
Users,
AsyncUsers,
@@ -145,6 +153,10 @@ def roles(self) -> Roles:
def data_retention(self) -> DataRetention:
return DataRetention(self._client)
+ @cached_property
+ def spend_limit(self) -> SpendLimit:
+ return SpendLimit(self._client)
+
@cached_property
def spend_alerts(self) -> SpendAlerts:
return SpendAlerts(self._client)
@@ -454,6 +466,10 @@ def roles(self) -> AsyncRoles:
def data_retention(self) -> AsyncDataRetention:
return AsyncDataRetention(self._client)
+ @cached_property
+ def spend_limit(self) -> AsyncSpendLimit:
+ return AsyncSpendLimit(self._client)
+
@cached_property
def spend_alerts(self) -> AsyncSpendAlerts:
return AsyncSpendAlerts(self._client)
@@ -782,6 +798,10 @@ def roles(self) -> RolesWithRawResponse:
def data_retention(self) -> DataRetentionWithRawResponse:
return DataRetentionWithRawResponse(self._projects.data_retention)
+ @cached_property
+ def spend_limit(self) -> SpendLimitWithRawResponse:
+ return SpendLimitWithRawResponse(self._projects.spend_limit)
+
@cached_property
def spend_alerts(self) -> SpendAlertsWithRawResponse:
return SpendAlertsWithRawResponse(self._projects.spend_alerts)
@@ -847,6 +867,10 @@ def roles(self) -> AsyncRolesWithRawResponse:
def data_retention(self) -> AsyncDataRetentionWithRawResponse:
return AsyncDataRetentionWithRawResponse(self._projects.data_retention)
+ @cached_property
+ def spend_limit(self) -> AsyncSpendLimitWithRawResponse:
+ return AsyncSpendLimitWithRawResponse(self._projects.spend_limit)
+
@cached_property
def spend_alerts(self) -> AsyncSpendAlertsWithRawResponse:
return AsyncSpendAlertsWithRawResponse(self._projects.spend_alerts)
@@ -912,6 +936,10 @@ def roles(self) -> RolesWithStreamingResponse:
def data_retention(self) -> DataRetentionWithStreamingResponse:
return DataRetentionWithStreamingResponse(self._projects.data_retention)
+ @cached_property
+ def spend_limit(self) -> SpendLimitWithStreamingResponse:
+ return SpendLimitWithStreamingResponse(self._projects.spend_limit)
+
@cached_property
def spend_alerts(self) -> SpendAlertsWithStreamingResponse:
return SpendAlertsWithStreamingResponse(self._projects.spend_alerts)
@@ -977,6 +1005,10 @@ def roles(self) -> AsyncRolesWithStreamingResponse:
def data_retention(self) -> AsyncDataRetentionWithStreamingResponse:
return AsyncDataRetentionWithStreamingResponse(self._projects.data_retention)
+ @cached_property
+ def spend_limit(self) -> AsyncSpendLimitWithStreamingResponse:
+ return AsyncSpendLimitWithStreamingResponse(self._projects.spend_limit)
+
@cached_property
def spend_alerts(self) -> AsyncSpendAlertsWithStreamingResponse:
return AsyncSpendAlertsWithStreamingResponse(self._projects.spend_alerts)
diff --git a/src/openai/resources/admin/organization/projects/spend_limit.py b/src/openai/resources/admin/organization/projects/spend_limit.py
new file mode 100644
index 0000000000..baca973214
--- /dev/null
+++ b/src/openai/resources/admin/organization/projects/spend_limit.py
@@ -0,0 +1,380 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ..... import _legacy_response
+from ....._types import Body, Query, Headers, NotGiven, not_given
+from ....._utils import path_template, maybe_transform, async_maybe_transform
+from ....._compat import cached_property
+from ....._resource import SyncAPIResource, AsyncAPIResource
+from ....._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ....._base_client import make_request_options
+from .....types.admin.organization.projects import spend_limit_update_params
+from .....types.admin.organization.projects.project_spend_limit import ProjectSpendLimit
+from .....types.admin.organization.projects.project_spend_limit_deleted import ProjectSpendLimitDeleted
+
+__all__ = ["SpendLimit", "AsyncSpendLimit"]
+
+
+class SpendLimit(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> SpendLimitWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers
+ """
+ return SpendLimitWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> SpendLimitWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/openai/openai-python#with_streaming_response
+ """
+ return SpendLimitWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ project_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectSpendLimit:
+ """
+ Get a project's hard spend limit.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return self._get(
+ path_template("/organization/projects/{project_id}/spend_limit", project_id=project_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=ProjectSpendLimit,
+ )
+
+ def update(
+ self,
+ project_id: str,
+ *,
+ currency: Literal["USD"],
+ interval: Literal["month"],
+ threshold_amount: int,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectSpendLimit:
+ """
+ Create or replace a project's hard spend limit.
+
+ Args:
+ currency: The currency for the threshold amount. Currently, only `USD` is supported.
+
+ interval: The time interval for evaluating spend against the threshold. Currently, only
+ `month` is supported.
+
+ threshold_amount: The hard spend limit amount, in cents.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return self._post(
+ path_template("/organization/projects/{project_id}/spend_limit", project_id=project_id),
+ body=maybe_transform(
+ {
+ "currency": currency,
+ "interval": interval,
+ "threshold_amount": threshold_amount,
+ },
+ spend_limit_update_params.SpendLimitUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=ProjectSpendLimit,
+ )
+
+ def delete(
+ self,
+ project_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectSpendLimitDeleted:
+ """
+ Delete a project's hard spend limit.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return self._delete(
+ path_template("/organization/projects/{project_id}/spend_limit", project_id=project_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=ProjectSpendLimitDeleted,
+ )
+
+
+class AsyncSpendLimit(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncSpendLimitWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncSpendLimitWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncSpendLimitWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/openai/openai-python#with_streaming_response
+ """
+ return AsyncSpendLimitWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ project_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectSpendLimit:
+ """
+ Get a project's hard spend limit.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return await self._get(
+ path_template("/organization/projects/{project_id}/spend_limit", project_id=project_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=ProjectSpendLimit,
+ )
+
+ async def update(
+ self,
+ project_id: str,
+ *,
+ currency: Literal["USD"],
+ interval: Literal["month"],
+ threshold_amount: int,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectSpendLimit:
+ """
+ Create or replace a project's hard spend limit.
+
+ Args:
+ currency: The currency for the threshold amount. Currently, only `USD` is supported.
+
+ interval: The time interval for evaluating spend against the threshold. Currently, only
+ `month` is supported.
+
+ threshold_amount: The hard spend limit amount, in cents.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return await self._post(
+ path_template("/organization/projects/{project_id}/spend_limit", project_id=project_id),
+ body=await async_maybe_transform(
+ {
+ "currency": currency,
+ "interval": interval,
+ "threshold_amount": threshold_amount,
+ },
+ spend_limit_update_params.SpendLimitUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=ProjectSpendLimit,
+ )
+
+ async def delete(
+ self,
+ project_id: str,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ProjectSpendLimitDeleted:
+ """
+ Delete a project's hard spend limit.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not project_id:
+ raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}")
+ return await self._delete(
+ path_template("/organization/projects/{project_id}/spend_limit", project_id=project_id),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=ProjectSpendLimitDeleted,
+ )
+
+
+class SpendLimitWithRawResponse:
+ def __init__(self, spend_limit: SpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = _legacy_response.to_raw_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = _legacy_response.to_raw_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = _legacy_response.to_raw_response_wrapper(
+ spend_limit.delete,
+ )
+
+
+class AsyncSpendLimitWithRawResponse:
+ def __init__(self, spend_limit: AsyncSpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = _legacy_response.async_to_raw_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = _legacy_response.async_to_raw_response_wrapper(
+ spend_limit.delete,
+ )
+
+
+class SpendLimitWithStreamingResponse:
+ def __init__(self, spend_limit: SpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = to_streamed_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = to_streamed_response_wrapper(
+ spend_limit.delete,
+ )
+
+
+class AsyncSpendLimitWithStreamingResponse:
+ def __init__(self, spend_limit: AsyncSpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ spend_limit.delete,
+ )
diff --git a/src/openai/resources/admin/organization/spend_limit.py b/src/openai/resources/admin/organization/spend_limit.py
new file mode 100644
index 0000000000..3b9394f615
--- /dev/null
+++ b/src/openai/resources/admin/organization/spend_limit.py
@@ -0,0 +1,318 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from .... import _legacy_response
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._utils import maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from ...._response import to_streamed_response_wrapper, async_to_streamed_response_wrapper
+from ...._base_client import make_request_options
+from ....types.admin.organization import spend_limit_update_params
+from ....types.admin.organization.organization_spend_limit import OrganizationSpendLimit
+from ....types.admin.organization.organization_spend_limit_deleted import OrganizationSpendLimitDeleted
+
+__all__ = ["SpendLimit", "AsyncSpendLimit"]
+
+
+class SpendLimit(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> SpendLimitWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers
+ """
+ return SpendLimitWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> SpendLimitWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/openai/openai-python#with_streaming_response
+ """
+ return SpendLimitWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> OrganizationSpendLimit:
+ """Get the organization's hard spend limit."""
+ return self._get(
+ "/organization/spend_limit",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=OrganizationSpendLimit,
+ )
+
+ def update(
+ self,
+ *,
+ currency: Literal["USD"],
+ interval: Literal["month"],
+ threshold_amount: int,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> OrganizationSpendLimit:
+ """
+ Create or replace the organization's hard spend limit.
+
+ Args:
+ currency: The currency for the threshold amount. Currently, only `USD` is supported.
+
+ interval: The time interval for evaluating spend against the threshold. Currently, only
+ `month` is supported.
+
+ threshold_amount: The hard spend limit amount, in cents.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._post(
+ "/organization/spend_limit",
+ body=maybe_transform(
+ {
+ "currency": currency,
+ "interval": interval,
+ "threshold_amount": threshold_amount,
+ },
+ spend_limit_update_params.SpendLimitUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=OrganizationSpendLimit,
+ )
+
+ def delete(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> OrganizationSpendLimitDeleted:
+ """Delete the organization's hard spend limit."""
+ return self._delete(
+ "/organization/spend_limit",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=OrganizationSpendLimitDeleted,
+ )
+
+
+class AsyncSpendLimit(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncSpendLimitWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/openai/openai-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncSpendLimitWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncSpendLimitWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/openai/openai-python#with_streaming_response
+ """
+ return AsyncSpendLimitWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> OrganizationSpendLimit:
+ """Get the organization's hard spend limit."""
+ return await self._get(
+ "/organization/spend_limit",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=OrganizationSpendLimit,
+ )
+
+ async def update(
+ self,
+ *,
+ currency: Literal["USD"],
+ interval: Literal["month"],
+ threshold_amount: int,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> OrganizationSpendLimit:
+ """
+ Create or replace the organization's hard spend limit.
+
+ Args:
+ currency: The currency for the threshold amount. Currently, only `USD` is supported.
+
+ interval: The time interval for evaluating spend against the threshold. Currently, only
+ `month` is supported.
+
+ threshold_amount: The hard spend limit amount, in cents.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return await self._post(
+ "/organization/spend_limit",
+ body=await async_maybe_transform(
+ {
+ "currency": currency,
+ "interval": interval,
+ "threshold_amount": threshold_amount,
+ },
+ spend_limit_update_params.SpendLimitUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=OrganizationSpendLimit,
+ )
+
+ async def delete(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> OrganizationSpendLimitDeleted:
+ """Delete the organization's hard spend limit."""
+ return await self._delete(
+ "/organization/spend_limit",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={"admin_api_key_auth": True},
+ ),
+ cast_to=OrganizationSpendLimitDeleted,
+ )
+
+
+class SpendLimitWithRawResponse:
+ def __init__(self, spend_limit: SpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = _legacy_response.to_raw_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = _legacy_response.to_raw_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = _legacy_response.to_raw_response_wrapper(
+ spend_limit.delete,
+ )
+
+
+class AsyncSpendLimitWithRawResponse:
+ def __init__(self, spend_limit: AsyncSpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = _legacy_response.async_to_raw_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = _legacy_response.async_to_raw_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = _legacy_response.async_to_raw_response_wrapper(
+ spend_limit.delete,
+ )
+
+
+class SpendLimitWithStreamingResponse:
+ def __init__(self, spend_limit: SpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = to_streamed_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = to_streamed_response_wrapper(
+ spend_limit.delete,
+ )
+
+
+class AsyncSpendLimitWithStreamingResponse:
+ def __init__(self, spend_limit: AsyncSpendLimit) -> None:
+ self._spend_limit = spend_limit
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ spend_limit.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ spend_limit.update,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ spend_limit.delete,
+ )
diff --git a/src/openai/types/admin/organization/__init__.py b/src/openai/types/admin/organization/__init__.py
index d14d8dce41..4efdf659e2 100644
--- a/src/openai/types/admin/organization/__init__.py
+++ b/src/openai/types/admin/organization/__init__.py
@@ -37,6 +37,7 @@
from .spend_alert_list_params import SpendAlertListParams as SpendAlertListParams
from .usage_embeddings_params import UsageEmbeddingsParams as UsageEmbeddingsParams
from .organization_spend_alert import OrganizationSpendAlert as OrganizationSpendAlert
+from .organization_spend_limit import OrganizationSpendLimit as OrganizationSpendLimit
from .usage_completions_params import UsageCompletionsParams as UsageCompletionsParams
from .usage_moderations_params import UsageModerationsParams as UsageModerationsParams
from .admin_api_key_list_params import AdminAPIKeyListParams as AdminAPIKeyListParams
@@ -45,6 +46,7 @@
from .certificate_update_params import CertificateUpdateParams as CertificateUpdateParams
from .spend_alert_create_params import SpendAlertCreateParams as SpendAlertCreateParams
from .spend_alert_update_params import SpendAlertUpdateParams as SpendAlertUpdateParams
+from .spend_limit_update_params import SpendLimitUpdateParams as SpendLimitUpdateParams
from .usage_embeddings_response import UsageEmbeddingsResponse as UsageEmbeddingsResponse
from .usage_completions_response import UsageCompletionsResponse as UsageCompletionsResponse
from .usage_moderations_response import UsageModerationsResponse as UsageModerationsResponse
@@ -67,6 +69,7 @@
from .certificate_deactivate_response import CertificateDeactivateResponse as CertificateDeactivateResponse
from .usage_web_search_calls_response import UsageWebSearchCallsResponse as UsageWebSearchCallsResponse
from .organization_spend_alert_deleted import OrganizationSpendAlertDeleted as OrganizationSpendAlertDeleted
+from .organization_spend_limit_deleted import OrganizationSpendLimitDeleted as OrganizationSpendLimitDeleted
from .usage_file_search_calls_response import UsageFileSearchCallsResponse as UsageFileSearchCallsResponse
from .usage_audio_transcriptions_params import UsageAudioTranscriptionsParams as UsageAudioTranscriptionsParams
from .usage_audio_transcriptions_response import UsageAudioTranscriptionsResponse as UsageAudioTranscriptionsResponse
diff --git a/src/openai/types/admin/organization/organization_spend_limit.py b/src/openai/types/admin/organization/organization_spend_limit.py
new file mode 100644
index 0000000000..89de914d27
--- /dev/null
+++ b/src/openai/types/admin/organization/organization_spend_limit.py
@@ -0,0 +1,37 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+
+__all__ = ["OrganizationSpendLimit", "Enforcement"]
+
+
+class Enforcement(BaseModel):
+ """The current enforcement state of the hard spend limit."""
+
+ status: Union[str, Literal["inactive", "enforcing"]]
+ """Whether the hard spend limit is currently enforcing."""
+
+
+class OrganizationSpendLimit(BaseModel):
+ """Represents a hard spend limit configured at the organization level."""
+
+ currency: Union[str, Literal["USD"]]
+ """The currency for the threshold amount. Currently, only `USD` is supported."""
+
+ enforcement: Enforcement
+ """The current enforcement state of the hard spend limit."""
+
+ interval: Union[str, Literal["month"]]
+ """The time interval for evaluating spend against the threshold.
+
+ Currently, only `month` is supported.
+ """
+
+ object: Literal["organization.spend_limit"]
+ """The object type, which is always `organization.spend_limit`."""
+
+ threshold_amount: int
+ """The hard spend limit amount, in cents."""
diff --git a/src/openai/types/admin/organization/organization_spend_limit_deleted.py b/src/openai/types/admin/organization/organization_spend_limit_deleted.py
new file mode 100644
index 0000000000..2ded2abedf
--- /dev/null
+++ b/src/openai/types/admin/organization/organization_spend_limit_deleted.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+
+__all__ = ["OrganizationSpendLimitDeleted"]
+
+
+class OrganizationSpendLimitDeleted(BaseModel):
+ """Confirmation payload returned after deleting an organization hard spend limit."""
+
+ deleted: bool
+ """Whether the hard spend limit was deleted."""
+
+ object: Literal["organization.spend_limit.deleted"]
+ """The object type, which is always `organization.spend_limit.deleted`."""
diff --git a/src/openai/types/admin/organization/projects/__init__.py b/src/openai/types/admin/organization/projects/__init__.py
index 1c510be58d..f92f701b50 100644
--- a/src/openai/types/admin/organization/projects/__init__.py
+++ b/src/openai/types/admin/organization/projects/__init__.py
@@ -16,6 +16,7 @@
from .api_key_list_params import APIKeyListParams as APIKeyListParams
from .group_create_params import GroupCreateParams as GroupCreateParams
from .project_spend_alert import ProjectSpendAlert as ProjectSpendAlert
+from .project_spend_limit import ProjectSpendLimit as ProjectSpendLimit
from .role_delete_response import RoleDeleteResponse as RoleDeleteResponse
from .user_delete_response import UserDeleteResponse as UserDeleteResponse
from .group_delete_response import GroupDeleteResponse as GroupDeleteResponse
@@ -29,8 +30,10 @@
from .project_model_permissions import ProjectModelPermissions as ProjectModelPermissions
from .spend_alert_create_params import SpendAlertCreateParams as SpendAlertCreateParams
from .spend_alert_update_params import SpendAlertUpdateParams as SpendAlertUpdateParams
+from .spend_limit_update_params import SpendLimitUpdateParams as SpendLimitUpdateParams
from .certificate_activate_params import CertificateActivateParams as CertificateActivateParams
from .project_spend_alert_deleted import ProjectSpendAlertDeleted as ProjectSpendAlertDeleted
+from .project_spend_limit_deleted import ProjectSpendLimitDeleted as ProjectSpendLimitDeleted
from .service_account_list_params import ServiceAccountListParams as ServiceAccountListParams
from .data_retention_update_params import DataRetentionUpdateParams as DataRetentionUpdateParams
from .certificate_activate_response import CertificateActivateResponse as CertificateActivateResponse
diff --git a/src/openai/types/admin/organization/projects/project_spend_limit.py b/src/openai/types/admin/organization/projects/project_spend_limit.py
new file mode 100644
index 0000000000..99971d727c
--- /dev/null
+++ b/src/openai/types/admin/organization/projects/project_spend_limit.py
@@ -0,0 +1,37 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Union
+from typing_extensions import Literal
+
+from ....._models import BaseModel
+
+__all__ = ["ProjectSpendLimit", "Enforcement"]
+
+
+class Enforcement(BaseModel):
+ """The current enforcement state of the hard spend limit."""
+
+ status: Union[str, Literal["inactive", "enforcing"]]
+ """Whether the hard spend limit is currently enforcing."""
+
+
+class ProjectSpendLimit(BaseModel):
+ """Represents a hard spend limit configured at the project level."""
+
+ currency: Union[str, Literal["USD"]]
+ """The currency for the threshold amount. Currently, only `USD` is supported."""
+
+ enforcement: Enforcement
+ """The current enforcement state of the hard spend limit."""
+
+ interval: Union[str, Literal["month"]]
+ """The time interval for evaluating spend against the threshold.
+
+ Currently, only `month` is supported.
+ """
+
+ object: Literal["project.spend_limit"]
+ """The object type, which is always `project.spend_limit`."""
+
+ threshold_amount: int
+ """The hard spend limit amount, in cents."""
diff --git a/src/openai/types/admin/organization/projects/project_spend_limit_deleted.py b/src/openai/types/admin/organization/projects/project_spend_limit_deleted.py
new file mode 100644
index 0000000000..c6dcc55550
--- /dev/null
+++ b/src/openai/types/admin/organization/projects/project_spend_limit_deleted.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ....._models import BaseModel
+
+__all__ = ["ProjectSpendLimitDeleted"]
+
+
+class ProjectSpendLimitDeleted(BaseModel):
+ """Confirmation payload returned after deleting a project hard spend limit."""
+
+ deleted: bool
+ """Whether the hard spend limit was deleted."""
+
+ object: Literal["project.spend_limit.deleted"]
+ """The object type, which is always `project.spend_limit.deleted`."""
diff --git a/src/openai/types/admin/organization/projects/spend_limit_update_params.py b/src/openai/types/admin/organization/projects/spend_limit_update_params.py
new file mode 100644
index 0000000000..34d75f4e41
--- /dev/null
+++ b/src/openai/types/admin/organization/projects/spend_limit_update_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["SpendLimitUpdateParams"]
+
+
+class SpendLimitUpdateParams(TypedDict, total=False):
+ currency: Required[Literal["USD"]]
+ """The currency for the threshold amount. Currently, only `USD` is supported."""
+
+ interval: Required[Literal["month"]]
+ """The time interval for evaluating spend against the threshold.
+
+ Currently, only `month` is supported.
+ """
+
+ threshold_amount: Required[int]
+ """The hard spend limit amount, in cents."""
diff --git a/src/openai/types/admin/organization/spend_limit_update_params.py b/src/openai/types/admin/organization/spend_limit_update_params.py
new file mode 100644
index 0000000000..34d75f4e41
--- /dev/null
+++ b/src/openai/types/admin/organization/spend_limit_update_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["SpendLimitUpdateParams"]
+
+
+class SpendLimitUpdateParams(TypedDict, total=False):
+ currency: Required[Literal["USD"]]
+ """The currency for the threshold amount. Currently, only `USD` is supported."""
+
+ interval: Required[Literal["month"]]
+ """The time interval for evaluating spend against the threshold.
+
+ Currently, only `month` is supported.
+ """
+
+ threshold_amount: Required[int]
+ """The hard spend limit amount, in cents."""
diff --git a/tests/api_resources/admin/organization/projects/test_spend_limit.py b/tests/api_resources/admin/organization/projects/test_spend_limit.py
new file mode 100644
index 0000000000..625e0efb5e
--- /dev/null
+++ b/tests/api_resources/admin/organization/projects/test_spend_limit.py
@@ -0,0 +1,279 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from openai import OpenAI, AsyncOpenAI
+from tests.utils import assert_matches_type
+from openai.types.admin.organization.projects import (
+ ProjectSpendLimit,
+ ProjectSpendLimitDeleted,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestSpendLimit:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: OpenAI) -> None:
+ spend_limit = client.admin.organization.projects.spend_limit.retrieve(
+ "proj_123",
+ )
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: OpenAI) -> None:
+ response = client.admin.organization.projects.spend_limit.with_raw_response.retrieve(
+ "proj_123",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: OpenAI) -> None:
+ with client.admin.organization.projects.spend_limit.with_streaming_response.retrieve(
+ "proj_123",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: OpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ client.admin.organization.projects.spend_limit.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_update(self, client: OpenAI) -> None:
+ spend_limit = client.admin.organization.projects.spend_limit.update(
+ project_id="proj_123",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: OpenAI) -> None:
+ response = client.admin.organization.projects.spend_limit.with_raw_response.update(
+ project_id="proj_123",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: OpenAI) -> None:
+ with client.admin.organization.projects.spend_limit.with_streaming_response.update(
+ project_id="proj_123",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: OpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ client.admin.organization.projects.spend_limit.with_raw_response.update(
+ project_id="",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+
+ @parametrize
+ def test_method_delete(self, client: OpenAI) -> None:
+ spend_limit = client.admin.organization.projects.spend_limit.delete(
+ "proj_123",
+ )
+ assert_matches_type(ProjectSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: OpenAI) -> None:
+ response = client.admin.organization.projects.spend_limit.with_raw_response.delete(
+ "proj_123",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: OpenAI) -> None:
+ with client.admin.organization.projects.spend_limit.with_streaming_response.delete(
+ "proj_123",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimitDeleted, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_delete(self, client: OpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ client.admin.organization.projects.spend_limit.with_raw_response.delete(
+ "",
+ )
+
+
+class TestAsyncSpendLimit:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None:
+ spend_limit = await async_client.admin.organization.projects.spend_limit.retrieve(
+ "proj_123",
+ )
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.admin.organization.projects.spend_limit.with_raw_response.retrieve(
+ "proj_123",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.admin.organization.projects.spend_limit.with_streaming_response.retrieve(
+ "proj_123",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = await response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncOpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ await async_client.admin.organization.projects.spend_limit.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncOpenAI) -> None:
+ spend_limit = await async_client.admin.organization.projects.spend_limit.update(
+ project_id="proj_123",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.admin.organization.projects.spend_limit.with_raw_response.update(
+ project_id="proj_123",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.admin.organization.projects.spend_limit.with_streaming_response.update(
+ project_id="proj_123",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = await response.parse()
+ assert_matches_type(ProjectSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncOpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ await async_client.admin.organization.projects.spend_limit.with_raw_response.update(
+ project_id="",
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncOpenAI) -> None:
+ spend_limit = await async_client.admin.organization.projects.spend_limit.delete(
+ "proj_123",
+ )
+ assert_matches_type(ProjectSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.admin.organization.projects.spend_limit.with_raw_response.delete(
+ "proj_123",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(ProjectSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.admin.organization.projects.spend_limit.with_streaming_response.delete(
+ "proj_123",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = await response.parse()
+ assert_matches_type(ProjectSpendLimitDeleted, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncOpenAI) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"):
+ await async_client.admin.organization.projects.spend_limit.with_raw_response.delete(
+ "",
+ )
diff --git a/tests/api_resources/admin/organization/test_spend_limit.py b/tests/api_resources/admin/organization/test_spend_limit.py
new file mode 100644
index 0000000000..4dd601a4d4
--- /dev/null
+++ b/tests/api_resources/admin/organization/test_spend_limit.py
@@ -0,0 +1,201 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from openai import OpenAI, AsyncOpenAI
+from tests.utils import assert_matches_type
+from openai.types.admin.organization import (
+ OrganizationSpendLimit,
+ OrganizationSpendLimitDeleted,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestSpendLimit:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: OpenAI) -> None:
+ spend_limit = client.admin.organization.spend_limit.retrieve()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: OpenAI) -> None:
+ response = client.admin.organization.spend_limit.with_raw_response.retrieve()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: OpenAI) -> None:
+ with client.admin.organization.spend_limit.with_streaming_response.retrieve() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_update(self, client: OpenAI) -> None:
+ spend_limit = client.admin.organization.spend_limit.update(
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: OpenAI) -> None:
+ response = client.admin.organization.spend_limit.with_raw_response.update(
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: OpenAI) -> None:
+ with client.admin.organization.spend_limit.with_streaming_response.update(
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_delete(self, client: OpenAI) -> None:
+ spend_limit = client.admin.organization.spend_limit.delete()
+ assert_matches_type(OrganizationSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ def test_raw_response_delete(self, client: OpenAI) -> None:
+ response = client.admin.organization.spend_limit.with_raw_response.delete()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ def test_streaming_response_delete(self, client: OpenAI) -> None:
+ with client.admin.organization.spend_limit.with_streaming_response.delete() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimitDeleted, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncSpendLimit:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncOpenAI) -> None:
+ spend_limit = await async_client.admin.organization.spend_limit.retrieve()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.admin.organization.spend_limit.with_raw_response.retrieve()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.admin.organization.spend_limit.with_streaming_response.retrieve() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = await response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncOpenAI) -> None:
+ spend_limit = await async_client.admin.organization.spend_limit.update(
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.admin.organization.spend_limit.with_raw_response.update(
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.admin.organization.spend_limit.with_streaming_response.update(
+ currency="USD",
+ interval="month",
+ threshold_amount=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = await response.parse()
+ assert_matches_type(OrganizationSpendLimit, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_delete(self, async_client: AsyncOpenAI) -> None:
+ spend_limit = await async_client.admin.organization.spend_limit.delete()
+ assert_matches_type(OrganizationSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_raw_response_delete(self, async_client: AsyncOpenAI) -> None:
+ response = await async_client.admin.organization.spend_limit.with_raw_response.delete()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ spend_limit = response.parse()
+ assert_matches_type(OrganizationSpendLimitDeleted, spend_limit, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_delete(self, async_client: AsyncOpenAI) -> None:
+ async with async_client.admin.organization.spend_limit.with_streaming_response.delete() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ spend_limit = await response.parse()
+ assert_matches_type(OrganizationSpendLimitDeleted, spend_limit, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
From 7a45217ccc77db778dff72a5637d5bcdd964b49e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 23 Jul 2026 16:16:55 +0000
Subject: [PATCH 3/3] release: 2.48.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 9 +++++++++
pyproject.toml | 2 +-
src/openai/_version.py | 2 +-
4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 3ab3b9e3de..d0e1cca504 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.47.0"
+ ".": "2.48.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 90e3d203a7..683068cda9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## 2.48.0 (2026-07-23)
+
+Full Changelog: [v2.47.0...v2.48.0](https://github.com/openai/openai-python/compare/v2.47.0...v2.48.0)
+
+### Features
+
+* **api:** accept `None` for prompt_cache_key/safety_identifier ([36820e6](https://github.com/openai/openai-python/commit/36820e69ba6cf1dc3f8d411e48a36e56084fbbc4))
+* **api:** add support for `spend_limit` admin apis ([1ff13af](https://github.com/openai/openai-python/commit/1ff13afb6e831394036686a1c352bbec6d704c68))
+
## 2.47.0 (2026-07-21)
Full Changelog: [v2.46.0...v2.47.0](https://github.com/openai/openai-python/compare/v2.46.0...v2.47.0)
diff --git a/pyproject.toml b/pyproject.toml
index c99f41b56f..5032fa5a30 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openai"
-version = "2.47.0"
+version = "2.48.0"
description = "The official Python library for the openai API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/openai/_version.py b/src/openai/_version.py
index 33a4084e62..8c2ee06274 100644
--- a/src/openai/_version.py
+++ b/src/openai/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "openai"
-__version__ = "2.47.0" # x-release-please-version
+__version__ = "2.48.0" # x-release-please-version