# Making Custom or Undocumented API Requests with the Anthropic Python SDK

> Learn to make custom or undocumented API requests with the Anthropic Python SDK using the request method and FinalRequestOptions for flexible API access.

- Repository: [Anthropic/anthropic-sdk-python](https://github.com/anthropics/anthropic-sdk-python)
- Tags: how-to-guide
- Published: 2026-02-23

---

**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`](https://github.com/anthropics/anthropic-sdk-python/blob/main/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`](https://github.com/anthropics/anthropic-sdk-python/blob/main/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 Preparation** – `FinalRequestOptions` (defined in [`src/anthropic/_models.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/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`](https://github.com/anthropics/anthropic-sdk-python/blob/main/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`](https://github.com/anthropics/anthropic-sdk-python/blob/main/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:

```python
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:

```python
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`:

```python
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:

```python
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`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_base_client.py) | Contains `BaseClient.request()`, `_build_request()`, and retry logic. |
| [`src/anthropic/_client.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_client.py) | Exposes public `Anthropic` and `AsyncAnthropic` classes that inherit from `BaseClient`. |
| [`src/anthropic/_models.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_models.py) | Defines `FinalRequestOptions` used to configure HTTP method, URL, headers, and body. |
| [`src/anthropic/_constants.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_constants.py) | Defines `RAW_RESPONSE_HEADER` (`X-Stainless-Raw-Response`) for raw response mode. |
| [`src/anthropic/_response.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/_response.py) | Implements `APIResponse` which wraps `httpx.Response` and handles deserialization. |

## Summary

- The **`request()`** method in `BaseClient` ([`src/anthropic/_base_client.py`](https://github.com/anthropics/anthropic-sdk-python/blob/main/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.