8181
8282RESERVED_HEADERS = ("x-api-key" ,)
8383
84+ NOT_PROVIDED = cast (None , object ())
8485
85- def _get_api_key (api_key : str | None = None ) -> str | None :
86+
87+ def _get_api_key (api_key : str | None = NOT_PROVIDED ) -> str | None :
8688 """Get the API key from the environment.
8789 Precedence:
88- 1. explicit argument
89- 2. LANGGRAPH_API_KEY
90- 3. LANGSMITH_API_KEY
91- 4. LANGCHAIN_API_KEY
90+ 1. explicit string argument
91+ 2. LANGGRAPH_API_KEY (if api_key not provided)
92+ 3. LANGSMITH_API_KEY (if api_key not provided)
93+ 4. LANGCHAIN_API_KEY (if api_key not provided)
94+
95+ Args:
96+ api_key: The API key to use. Can be:
97+ - A string: use this exact API key
98+ - None: explicitly skip loading from environment
99+ - NOT_PROVIDED (default): auto-load from environment variables
92100 """
93- if api_key :
101+ if isinstance ( api_key , str ) :
94102 return api_key
95- for prefix in ["LANGGRAPH" , "LANGSMITH" , "LANGCHAIN" ]:
96- if env := os .getenv (f"{ prefix } _API_KEY" ):
97- return env .strip ().strip ('"' ).strip ("'" )
98- return None # type: ignore
103+ if api_key is NOT_PROVIDED :
104+ # api_key is not explicitly provided, try to load from environment
105+ for prefix in ["LANGGRAPH" , "LANGSMITH" , "LANGCHAIN" ]:
106+ if env := os .getenv (f"{ prefix } _API_KEY" ):
107+ return env .strip ().strip ('"' ).strip ("'" )
108+ # api_key is explicitly None, don't load from environment
109+ return None
99110
100111
101112def _get_headers (
102- api_key : str | None , custom_headers : Mapping [str , str ] | None
113+ api_key : str | None ,
114+ custom_headers : Mapping [str , str ] | None ,
103115) -> dict [str , str ]:
104116 """Combine api_key and custom user-provided headers."""
105117 custom_headers = custom_headers or {}
@@ -111,9 +123,9 @@ def _get_headers(
111123 "User-Agent" : f"langgraph-sdk-py/{ langgraph_sdk .__version__ } " ,
112124 ** custom_headers ,
113125 }
114- api_key = _get_api_key (api_key )
115- if api_key :
116- headers ["x-api-key" ] = api_key
126+ resolved_api_key = _get_api_key (api_key )
127+ if resolved_api_key :
128+ headers ["x-api-key" ] = resolved_api_key
117129
118130 return headers
119131
@@ -164,7 +176,7 @@ def _get_run_metadata_from_response(
164176def get_client (
165177 * ,
166178 url : str | None = None ,
167- api_key : str | None = None ,
179+ api_key : str | None = NOT_PROVIDED ,
168180 headers : Mapping [str , str ] | None = None ,
169181 timeout : TimeoutTypes | None = None ,
170182) -> LangGraphClient :
@@ -179,12 +191,13 @@ def get_client(
179191 - If `None`, the client first attempts an in-process connection via ASGI transport.
180192 If that fails, it falls back to `http://localhost:8123`.
181193 api_key:
182- API key for authentication. If omitted, the client reads from environment
183- variables in the following order:
184- 1. Function argument
185- 2. `LANGGRAPH_API_KEY`
186- 3. `LANGSMITH_API_KEY`
187- 4. `LANGCHAIN_API_KEY`
194+ API key for authentication. Can be:
195+ - A string: use this exact API key
196+ - `None`: explicitly skip loading from environment variables
197+ - Not provided (default): auto-load from environment in this order:
198+ 1. `LANGGRAPH_API_KEY`
199+ 2. `LANGSMITH_API_KEY`
200+ 3. `LANGCHAIN_API_KEY`
188201 headers:
189202 Additional HTTP headers to include in requests. Merged with authentication headers.
190203 timeout:
@@ -225,6 +238,18 @@ async def my_node(...):
225238 input={"messages": [{"role": "user", "content": "Foo"}]},
226239 )
227240 ```
241+
242+ ???+ example "Skip auto-loading API key from environment:"
243+
244+ ```python
245+ from langgraph_sdk import get_client
246+
247+ # Don't load API key from environment variables
248+ client = get_client(
249+ url="http://localhost:8123",
250+ api_key=None
251+ )
252+ ```
228253 """
229254
230255 transport : httpx .AsyncBaseTransport | None = None
@@ -3471,20 +3496,21 @@ async def list_namespaces(
34713496def get_sync_client (
34723497 * ,
34733498 url : str | None = None ,
3474- api_key : str | None = None ,
3499+ api_key : str | None = NOT_PROVIDED ,
34753500 headers : Mapping [str , str ] | None = None ,
34763501 timeout : TimeoutTypes | None = None ,
34773502) -> SyncLangGraphClient :
34783503 """Get a synchronous LangGraphClient instance.
34793504
34803505 Args:
34813506 url: The URL of the LangGraph API.
3482- api_key: The API key. If not provided, it will be read from the environment.
3483- Precedence:
3484- 1. explicit argument
3485- 2. LANGGRAPH_API_KEY
3486- 3. LANGSMITH_API_KEY
3487- 4. LANGCHAIN_API_KEY
3507+ api_key: API key for authentication. Can be:
3508+ - A string: use this exact API key
3509+ - `None`: explicitly skip loading from environment variables
3510+ - Not provided (default): auto-load from environment in this order:
3511+ 1. `LANGGRAPH_API_KEY`
3512+ 2. `LANGSMITH_API_KEY`
3513+ 3. `LANGCHAIN_API_KEY`
34883514 headers: Optional custom headers
34893515 timeout: Optional timeout configuration for the HTTP client.
34903516 Accepts an httpx.Timeout instance, a float (seconds), or a tuple of timeouts.
@@ -3505,6 +3531,18 @@ def get_sync_client(
35053531 # example usage: client.<model>.<method_name>()
35063532 assistant = client.assistants.get(assistant_id="some_uuid")
35073533 ```
3534+
3535+ ???+ example "Skip auto-loading API key from environment:"
3536+
3537+ ```python
3538+ from langgraph_sdk import get_sync_client
3539+
3540+ # Don't load API key from environment variables
3541+ client = get_sync_client(
3542+ url="http://localhost:8123",
3543+ api_key=None
3544+ )
3545+ ```
35083546 """
35093547
35103548 if url is None :
0 commit comments