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:

  1. Option PreparationFinalRequestOptions (defined in src/anthropic/_models.py) validates and stores the HTTP verb, path, and payload.
  2. Request Building_build_request constructs an httpx.Request object, injecting authentication headers and the base URL.
  3. Execution – The underlying httpx.Client (or AsyncClient) sends the request via self._client.send.
  4. Retry Handling – The client automatically retries on rate limits or transient errors using _sleep_for_retry and idempotency keys.
  5. Response Wrapping – The raw httpx.Response is wrapped in an APIResponse object (src/anthropic/_response.py), which handles deserialization based on the cast_to parameter 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 in BaseClient (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-Response header (or RAW_RESPONSE_HEADER constant) to receive raw httpx.Response objects 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →