Making Custom or Undocumented API Requests with the Anthropic Python SDK
Use the request() method on Anthropic or AsyncAnthropic clients with a FinalRequestOptions object to call any endpoint, or set the X-Stainless-Raw-Response header to receive raw httpx.Response objects instead of parsed models.
The Anthropic Python SDK provides first-class methods for chat completions and message handling, but you may need to access beta endpoints or experimental features not yet exposed in the high-level API. The anthropics/anthropic-sdk-python repository exposes low-level request primitives in src/anthropic/_base_client.py that allow you to construct arbitrary HTTP calls while retaining the SDK's authentication, retry logic, and response handling.
How the SDK Handles Custom Requests Architecturally
Every HTTP call in the Anthropic SDK flows through the request method defined in BaseClient (src/anthropic/_base_client.py). This method accepts a FinalRequestOptions object that encapsulates all HTTP semantics—method, URL, headers, query parameters, JSON body, and file uploads.
The Request Pipeline
When you invoke client.request(), the SDK executes the following sequence:
- Option Preparation –
FinalRequestOptions(defined insrc/anthropic/_models.py) validates and stores the HTTP verb, path, and payload. - Request Building –
_build_requestconstructs anhttpx.Requestobject, injecting authentication headers and the base URL. - Execution – The underlying
httpx.Client(orAsyncClient) sends the request viaself._client.send. - Retry Handling – The client automatically retries on rate limits or transient errors using
_sleep_for_retryand idempotency keys. - Response Wrapping – The raw
httpx.Responseis wrapped in anAPIResponseobject (src/anthropic/_response.py), which handles deserialization based on thecast_toparameter you provide.
Raw Response Mode
To bypass model parsing and receive the underlying httpx.Response object, set the X-Stainless-Raw-Response header (defined as RAW_RESPONSE_HEADER in src/anthropic/_constants.py) to "true". When this header is present, the SDK returns the raw response instead of attempting to parse it into a Pydantic model.
Making Custom GET, POST, and Raw Requests
The Anthropic and AsyncAnthropic classes expose the full request interface, allowing you to target any path in the API.
Synchronous Custom Requests
Use FinalRequestOptions.construct to build the request descriptor, then pass it to client.request with a type hint for deserialization:
from anthropic import Anthropic
from anthropic._models import FinalRequestOptions
client = Anthropic(api_key="YOUR_API_KEY")
# Custom GET request to an undocumented endpoint
options = FinalRequestOptions.construct(
method="get",
url="/v1/experimental/features",
params={"limit": 10},
headers={"X-Custom-Header": "value"},
)
# Deserialize JSON response into a dict
result = client.request(dict, options)
print(result)
For POST requests with a JSON body, use the json_data parameter:
post_options = FinalRequestOptions.construct(
method="post",
url="/v1/beta/feedback",
json_data={"message_id": "msg_123", "rating": 5},
)
feedback = client.request(dict, post_options)
Asynchronous Custom Requests
The AsyncAnthropic client follows the same pattern using await:
import asyncio
from anthropic import AsyncAnthropic
from anthropic._models import FinalRequestOptions
async def fetch_experimental():
async_client = AsyncAnthropic(api_key="YOUR_API_KEY")
opts = FinalRequestOptions.construct(
method="get",
url="/v1/experimental/config",
)
result = await async_client.request(dict, opts)
return result
# Run the async function
config = asyncio.run(fetch_experimental())
Accessing Raw HTTP Responses
To inspect headers, status codes, or stream raw bytes without SDK parsing, import the raw response constant and set it in your options:
from anthropic._constants import RAW_RESPONSE_HEADER
raw_options = FinalRequestOptions.construct(
method="get",
url="/v1/health",
headers={RAW_RESPONSE_HEADER: "true"},
)
# Returns an httpx.Response object, not a dict
raw_response = client.request(dict, raw_options)
print(raw_response.status_code) # 200
print(raw_response.headers["content-type"])
print(raw_response.text)
Key Source Files for Custom Requests
Understanding these files helps you trace how custom requests flow through the SDK:
| File | Purpose |
|---|---|
src/anthropic/_base_client.py |
Contains BaseClient.request(), _build_request(), and retry logic. |
src/anthropic/_client.py |
Exposes public Anthropic and AsyncAnthropic classes that inherit from BaseClient. |
src/anthropic/_models.py |
Defines FinalRequestOptions used to configure HTTP method, URL, headers, and body. |
src/anthropic/_constants.py |
Defines RAW_RESPONSE_HEADER (X-Stainless-Raw-Response) for raw response mode. |
src/anthropic/_response.py |
Implements APIResponse which wraps httpx.Response and handles deserialization. |
Summary
- The
request()method inBaseClient(src/anthropic/_base_client.py) is the universal entry point for all HTTP traffic in the Anthropic SDK. - Use
FinalRequestOptions.construct()to build request configurations for undocumented endpoints, specifying method, URL, params, headers, and JSON body. - Both synchronous (
Anthropic) and asynchronous (AsyncAnthropic) clients support custom requests with identical semantics. - Set the
X-Stainless-Raw-Responseheader (orRAW_RESPONSE_HEADERconstant) to receive rawhttpx.Responseobjects instead of parsed models. - The SDK automatically applies authentication, retries, and timeouts to custom requests just as it does for official resource methods.
Frequently Asked Questions
How do I access endpoints that are not yet supported by the SDK?
Use the low-level request() method available on any Anthropic or AsyncAnthropic client instance. Construct a FinalRequestOptions object with the specific HTTP method and path, then pass it to client.request(cast_type, options). This bypasses the high-level resource abstractions while retaining authentication and retry logic.
Can I receive the raw HTTP response instead of a parsed Pydantic model?
Yes. Import RAW_RESPONSE_HEADER from anthropic._constants and set it to "true" in your request headers. When this header is present, the SDK returns the underlying httpx.Response object, allowing you to inspect status codes, headers, and raw body content without automatic deserialization.
Do custom requests support automatic retries and authentication?
Absolutely. Because custom requests flow through the same BaseClient.request() pipeline as official methods, they automatically inherit the SDK's retry policies, timeout handling, and API key authentication. The _build_request method injects the Authorization header and the retry logic in _sleep_for_retry handles rate limits and transient errors.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →