Skip to content

Configuration

The simplest way to create a client with this SDK is through Anthropic::client():

$client = Anthropic::client('your-api-key');

This uses auto-discovered defaults: the official Anthropic API endpoint, a PSR-18 HTTP client found via php-http/discovery, and standard headers. For most projects, this is enough.

When you need to customize anything, use the factory.

Factory options

The factory lets you configure every aspect of the client:

$client = Anthropic::factory()
    ->withApiKey('your-api-key')
    ->withBaseUri('anthropic.example.com/v1')
    ->withHttpClient($httpClient)
    ->withHttpHeader('X-Custom-Header', 'value')
    ->withQueryParam('my-param', 'bar')
    ->withStreamHandler($streamHandler)
    ->make();

Call make() at the end to create the client. Each with* method returns the factory, so you can chain them.

API key

->withApiKey('your-api-key')

Required. The client sends this as a x-api-key header on every request. Leading and trailing whitespace is trimmed automatically.

Base URI

->withBaseUri('anthropic.example.com/v1')

Defaults to api.anthropic.com/v1. Override this when you're routing through a proxy, a gateway, or a self-hosted endpoint.

HTTP client

->withHttpClient(new \GuzzleHttp\Client(['timeout' => 120]))

Provide your own PSR-18 HTTP client. If you don't set one, the factory uses php-http/discovery to find a compatible client in your project automatically.

Custom headers

->withHttpHeader('X-Custom-Header', 'value')

Adds a header to every request. Call it multiple times for multiple headers. The client always sends anthropic-version: 2023-06-01 and the authorization header; your custom headers are added on top.

Query parameters

->withQueryParam('my-param', 'bar')

Adds a query parameter to every request URL. Useful for routing or analytics parameters required by proxy setups.

Stream handler

->withStreamHandler(fn (RequestInterface $request): ResponseInterface =>
    $httpClient->send($request, ['stream' => true])
)

Custom handler for streaming requests. The handler receives a PSR-7 RequestInterface and must return a PSR-7 ResponseInterface with a streaming body.

You only need this for HTTP clients other than Guzzle or Symfony. Both of those are detected automatically and handled without any extra configuration.

Beta features

Anthropic's beta features are opt-in via the anthropic-beta header. This SDK lets you enable them per request by passing a betas array alongside your normal parameters:

$response = $client->messages()->create([
    'model' => 'claude-opus-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Hello!'],
    ],
    'betas' => [
        'interleaved-thinking-2025-05-14',
        'extended-cache-ttl-2025-04-11',
    ],
]);

The SDK pulls betas out of the parameters before serialization, so nothing leaks into the JSON body or query string. It becomes a comma-separated anthropic-beta header on that one request only.

If some beta is enabled for every request in your app, set it globally on the factory and skip the per-call array:

$client = Anthropic::factory()
    ->withApiKey('your-api-key')
    ->withHttpHeader('anthropic-beta', 'interleaved-thinking-2025-05-14')
    ->make();

Global and per-request combine. If you set anthropic-beta: interleaved-thinking-2025-05-14 globally and pass betas: ['files-api-2025-04-14'] on one call, that call sends both, de-duplicated.

Some resources require a specific beta header to work at all. The SDK auto-injects those for you, so you never have to type the version string for the resource you're already using. You only pass betas when you want to add additional ones on top.

For how beta headers work, multi-beta syntax, and version naming conventions, see the Beta headers reference on the Anthropic docs. Individual beta feature names are documented on the page for the feature they gate (Files API, extended cache TTL, interleaved thinking, and so on).

HTTP client setup

Guzzle

Guzzle is the most common choice. Everything works out of the box, including streaming:

composer require guzzlehttp/guzzle
$client = Anthropic::factory()
    ->withApiKey('your-api-key')
    ->withHttpClient(new \GuzzleHttp\Client([
        'timeout' => 120,
        'connect_timeout' => 5,
    ]))
    ->make();

No stream handler needed. The factory detects Guzzle and configures streaming automatically.

Symfony HTTP Client

Symfony's HTTP client also works without a custom stream handler:

composer require symfony/http-client
use Symfony\Component\HttpClient\Psr18Client;

$client = Anthropic::factory()
    ->withApiKey('your-api-key')
    ->withHttpClient(new Psr18Client())
    ->make();

Other PSR-18 clients

For any other PSR-18 client, you'll need to provide a stream handler that tells the client how to return a streaming response:

$httpClient = new SomeOtherHttpClient();

$client = Anthropic::factory()
    ->withApiKey('your-api-key')
    ->withHttpClient($httpClient)
    ->withStreamHandler(function (RequestInterface $request) use ($httpClient): ResponseInterface {
        // Your client's way of returning a streaming response
        return $httpClient->sendRequest($request);
    })
    ->make();

Without a stream handler, calling createStreamed() will throw an exception.

Timeout configuration

The default timeout depends on your HTTP client. For long-running requests (large context windows, extended thinking, code execution), you'll likely want to increase it.

With Guzzle:

$client = Anthropic::factory()
    ->withApiKey('your-api-key')
    ->withHttpClient(new \GuzzleHttp\Client(['timeout' => 300]))
    ->make();

With Symfony:

use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Psr18Client;

$httpClient = HttpClient::create(['timeout' => 300]);
$client = Anthropic::factory()
    ->withApiKey('your-api-key')
    ->withHttpClient(new Psr18Client($httpClient))
    ->make();

PSR-18 client discovery

When you don't provide an HTTP client, the factory uses php-http/discovery to find one. This works if your project has any PSR-18 compatible client installed (Guzzle, Symfony HTTP Client, Buzz, etc.).

If discovery fails, you'll get an error at runtime. Either install a client explicitly:

composer require guzzlehttp/guzzle

Or allow the php-http/discovery Composer plugin to install one automatically:

composer config allow-plugins.php-http/discovery true
Scroll to top