# Anthropic PHP

**Package:** Anthropic PHP | **Version:** 1 | **URL:** https://mozex.dev/docs/anthropic-php/v1

---

**Anthropic PHP** is a community-maintained PHP API client that allows you to interact with the [Anthropic API](https://docs.anthropic.com/claude/docs/intro-to-claude).

> **Note:** If you want to use the **Anthropic PHP** in Laravel, take a look at the [mozex/anthropic-laravel](https://mozex.dev/docs/anthropic-laravel/v1) repository.

## Get Started

> **Requires [PHP 8.2+](https://php.net/releases/)**

First, install Anthropic via the [Composer](https://getcomposer.org/) package manager:

```bash
composer require mozex/anthropic-php
```

Ensure that the `php-http/discovery` composer plugin is allowed to run or install a client manually if your project does not already have a PSR-18 client integrated.
```bash
composer require guzzlehttp/guzzle
```

Then, interact with Anthropic's API:

```php
$yourApiKey = getenv('YOUR_API_KEY');
$client = Anthropic::client($yourApiKey);

$result = $client->messages()->create([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Hello!'],
    ],
]);

echo $result->content[0]->text; // Hello! How can I assist you today?
```

If necessary, it is possible to configure and create a separate client.

```php
$yourApiKey = getenv('YOUR_API_KEY');

$client = Anthropic::factory()
    ->withApiKey($yourApiKey)
    ->withBaseUri('anthropic.example.com/v1') // default: api.anthropic.com/v1
    ->withHttpClient($httpClient = new \GuzzleHttp\Client([])) // default: HTTP client found using PSR-18 HTTP Client Discovery
    ->withHttpHeader('X-My-Header', 'foo')
    ->withQueryParam('my-param', 'bar')
    ->withStreamHandler(fn (RequestInterface $request): ResponseInterface => $httpClient->send($request, [
        'stream' => true // Allows to provide a custom stream handler for the http client.
    ]))
    ->make();
```

## Usage

### `Messages` Resource

#### `create`

Creates a completion for structured list of input messages.

```php
$response = $client->messages()->create([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Hello, world'],
    ],
]);

$response->id; // 'msg_01BSy0WCV7QR2adFBauynAX7'
$response->type; // 'message'
$response->role; // 'assistant'
$response->model; // 'claude-sonnet-4-6'
$response->stop_sequence; // null
$response->stop_reason; // 'end_turn'

foreach ($response->content as $result) {
    $result->type; // 'text'
    $result->text; // 'Hello! It's nice to meet you. How can I assist you today?'
}

$response->usage->inputTokens; // 10,
$response->usage->outputTokens; // 19,
$response->usage->cacheCreationInputTokens; // 0,
$response->usage->cacheReadInputTokens; // 0,
$response->usage->cacheCreation; // null or CreateResponseUsageCacheCreation
$response->usage->cacheCreation?->ephemeral5mInputTokens; // 456
$response->usage->cacheCreation?->ephemeral1hInputTokens; // 100
$response->usage->serviceTier; // 'standard', 'priority', 'batch', or null
$response->usage->serverToolUse; // null or CreateResponseUsageServerToolUse
$response->usage->serverToolUse?->webSearchRequests; // 3

$response->toArray(); // ['id' => 'msg_01BSy0WCV7QR2adFBauynAX7', ...]
```

Creates a completion for the structured list of input messages with a tool call.

```php
$response = $client->messages()->create([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'What is the weather like in San Francisco?'],
    ],
    'tools' => [
        [
            'name' => 'get_weather',
            'description' => 'Get the current weather in a given location',
            'input_schema' => [
                'type' => 'object',
                'properties' => [
                    'location' => [
                        'type' => 'string',
                        'description' => 'The city and state, e.g. San Francisco, CA'
                    ],
                    'unit' => [
                        'type' => 'string',
                        'enum' => ['celsius', 'fahrenheit'],
                        'description' => 'The unit of temperature, either \"celsius\" or \"fahrenheit\"'
                    ]
                ],
                'required' => ['location']
            ]
        ]
    ]
]);

$response->id; // 'msg_01BSy0WCV7QR2adFBauynAX7'
$response->type; // 'message'
$response->role; // 'assistant'
$response->model; // 'claude-sonnet-4-6'
$response->stop_sequence; // null
$response->stop_reason; // 'tool_use'

$response->content[0]->type; // 'text'
$response->content[0]->text; // 'I'll help you check the current weather in San Francisco. I'll use the get_weather function, assuming San Francisco, CA as the location.'

$response->content[1]->type; // 'tool_use'
$response->content[1]->id; // 'toolu_01RnYGkgJusAzXvcySfZ2Dq7'
$response->content[1]->name; // 'get_weather'
$response->content[1]->input['location']; // 'San Francisco, CA'
$response->content[1]->input['unit']; // 'fahrenheit'

$response->usage->inputTokens; // 448,
$response->usage->outputTokens; // 87,
$response->usage->cacheCreationInputTokens; // 0,
$response->usage->cacheReadInputTokens; // 0,

$response->toArray(); // ['id' => 'msg_01BSy0WCV7QR2adFBauynAX7', ...]
```

Creates a completion with adaptive thinking. This is the recommended approach for Claude Opus 4.6 and Sonnet 4.6, where the model decides when and how much to think based on the request complexity.

```php
$response = $client->messages()->create([
    'model' => 'claude-opus-4-6',
    'max_tokens' => 16000,
    'thinking' => [
        'type' => 'adaptive',
    ],
    'messages' => [
        ['role' => 'user', 'content' => 'Explain why the sum of two even numbers is always even.'],
    ],
]);

foreach ($response->content as $block) {
    $block->type; // 'thinking', 'redacted_thinking', or 'text'

    if ($block->type === 'thinking') {
        $block->thinking; // 'Let me analyze this step by step...'
        $block->signature; // 'WaUjzkypQ2mUEVM36O2TxuC06KN8xyfbJwyem...'
    }

    if ($block->type === 'redacted_thinking') {
        $block->data; // 'EmwKAhgBEgy3va3pzix/LafPsn4a'
    }

    if ($block->type === 'text') {
        $block->text; // 'Based on my analysis...'
    }
}
```

Use the `display` option to control how thinking content appears in responses. With `'summarized'` (the default), thinking blocks contain a summary of the model's reasoning. With `'omitted'`, the `thinking` field is empty but the `signature` is still present for multi-turn continuity.

```php
$response = $client->messages()->create([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 16000,
    'thinking' => [
        'type' => 'adaptive',
        'display' => 'omitted',
    ],
    'messages' => [
        ['role' => 'user', 'content' => 'What is 27 * 453?'],
    ],
]);

$response->content[0]->type; // 'thinking'
$response->content[0]->thinking; // '' (empty when omitted)
$response->content[0]->signature; // 'EosnCkYICxIMMb3LzNrMu...' (always present)
$response->content[1]->text; // 'The answer is 12,231.'
```

Use `output_config.effort` to guide how much the model thinks. Accepts `'max'` (Opus 4.6 only), `'high'` (default), `'medium'`, or `'low'`. With lower effort, the model may skip thinking entirely for simple queries.

```php
$response = $client->messages()->create([
    'model' => 'claude-opus-4-6',
    'max_tokens' => 16000,
    'thinking' => [
        'type' => 'adaptive',
    ],
    'output_config' => [
        'effort' => 'medium',
    ],
    'messages' => [
        ['role' => 'user', 'content' => 'What is the capital of France?'],
    ],
]);
```

For older models (Claude Sonnet 3.7, Opus 4.5, Sonnet 4.5), use `budget_tokens` instead of adaptive thinking.

```php
$response = $client->messages()->create([
    'model' => 'claude-sonnet-4-5',
    'max_tokens' => 16000,
    'thinking' => [
        'type' => 'enabled',
        'budget_tokens' => 10000,
    ],
    'messages' => [
        ['role' => 'user', 'content' => 'Are there an infinite number of prime numbers such that n mod 4 == 3?'],
    ],
]);
```

Creates a completion with web search. Claude searches the web, and the response contains `server_tool_use`, `web_search_tool_result`, and `text` blocks with citations back to the sources.

```php
$response = $client->messages()->create([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'tools' => [['type' => 'web_search_20250305', 'name' => 'web_search']],
    'messages' => [
        ['role' => 'user', 'content' => 'When was Claude Shannon born?'],
    ],
]);

// The search query Claude chose
$response->content[0]->type; // 'server_tool_use'
$response->content[0]->id; // 'srvtoolu_01WYG3ziw53XMcoyKL4XcZmE'
$response->content[0]->name; // 'web_search'
$response->content[0]->input; // ['query' => 'claude shannon birth date']

// Search results (linked back to the server_tool_use by tool_use_id)
$response->content[1]->type; // 'web_search_tool_result'
$response->content[1]->tool_use_id; // 'srvtoolu_01WYG3ziw53XMcoyKL4XcZmE'
$response->content[1]->content[0]['title']; // 'Claude Shannon - Wikipedia'
$response->content[1]->content[0]['url']; // 'https://en.wikipedia.org/wiki/Claude_Shannon'

// Claude's answer with citations to sources
$response->content[2]->type; // 'text'
$response->content[2]->text; // 'Claude Shannon was born on April 30, 1916...'
$response->content[2]->citations[0]['type']; // 'web_search_result_location'
$response->content[2]->citations[0]['title']; // 'Claude Shannon - Wikipedia'
$response->content[2]->citations[0]['url']; // 'https://en.wikipedia.org/wiki/Claude_Shannon'
$response->content[2]->citations[0]['cited_text']; // 'Claude Elwood Shannon (April 30, 1916 – ...'

$response->usage->serverToolUse?->webSearchRequests; // 1
```

Creates a completion with code execution. Claude runs code in a sandboxed container and returns the output. The response may include `bash_code_execution_tool_result` and `text_editor_code_execution_tool_result` blocks depending on which operations Claude performs.

```php
$response = $client->messages()->create([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 4096,
    'tools' => [['type' => 'code_execution_20250825', 'name' => 'code_execution']],
    'messages' => [
        ['role' => 'user', 'content' => 'Run this Python code: print(sum(range(1, 101)))'],
    ],
]);

$response->content[0]->type; // 'server_tool_use'
$response->content[0]->name; // 'bash_code_execution'

$response->content[1]->type; // 'bash_code_execution_tool_result'
$response->content[1]->tool_use_id; // 'srvtoolu_01EWAZ5utP321iRHFdsvbWEV'
$response->content[1]->content['type']; // 'bash_code_execution_result'
$response->content[1]->content['stdout']; // '5050'
$response->content[1]->content['return_code']; // 0

// Container persists across turns for multi-step code execution
$response->container['id']; // 'container_011CZcynv5pD9zSXC9hAyeS2'
$response->container['expires_at']; // '2026-04-01T12:28:18.898511Z'
```

The same `tool_use_id` + `content` pattern applies to `web_fetch_tool_result`, `code_execution_tool_result`, and `tool_search_tool_result` blocks.

Creates a completion with document citations. Enable citations on document blocks, and the response will contain multiple text blocks where each cited claim includes a `citations` array pointing to exact locations in your source documents.

```php
$response = $client->messages()->create([
    'model' => 'claude-opus-4-6',
    'max_tokens' => 1024,
    'messages' => [
        [
            'role' => 'user',
            'content' => [
                [
                    'type' => 'document',
                    'source' => [
                        'type' => 'text',
                        'media_type' => 'text/plain',
                        'data' => 'The grass is green. The sky is blue.',
                    ],
                    'title' => 'My Document',
                    'citations' => ['enabled' => true],
                ],
                [
                    'type' => 'text',
                    'text' => 'What color is the grass and sky?',
                ],
            ],
        ],
    ],
]);

// Uncited text
$response->content[0]->type; // 'text'
$response->content[0]->text; // 'According to the document, '
$response->content[0]->citations; // null

// Cited claim with char_location (plain text documents)
$response->content[1]->type; // 'text'
$response->content[1]->text; // 'the grass is green'
$response->content[1]->citations[0]['type']; // 'char_location'
$response->content[1]->citations[0]['cited_text']; // 'The grass is green.'
$response->content[1]->citations[0]['document_index']; // 0
$response->content[1]->citations[0]['document_title']; // 'My Document'
$response->content[1]->citations[0]['start_char_index']; // 0
$response->content[1]->citations[0]['end_char_index']; // 20
```

Five citation location types exist depending on the document source: `char_location` (plain text), `page_location` (PDFs), `content_block_location` (custom content), `web_search_result_location` (web search), and `search_result_location` (search results).

When streaming, citations arrive as `citations_delta` events on the delta object:

```php
foreach ($stream as $response) {
    if ($response->delta->type === 'citations_delta') {
        $response->delta->citation['type']; // 'char_location'
        $response->delta->citation['cited_text']; // 'The grass is green.'
    }
}
```

#### `countTokens`

Counts the number of tokens in a message without creating it.

```php
$response = $client->messages()->countTokens([
    'model' => 'claude-sonnet-4-6',
    'messages' => [
        ['role' => 'user', 'content' => 'Hello, world'],
    ],
]);

$response->inputTokens; // 2095
```

#### `create streamed`

Creates a streamed completion for structured list of input messages.

```php
$stream = $client->messages()->createStreamed([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Hello!'],
    ],
]);

foreach($stream as $response){
    $response->toArray();
}
// 1. iteration
[
    'type' => 'message_start',
    'message' => [
        'id' => 'msg_01SX1jLtTXgtJwB2EpSRNutG',
        'type' => 'message',
        'role' => 'assistant',
        'content' => [],
        'model' => 'claude-sonnet-4-6',
        'stop_reason' => null,
        'stop_sequence' => null,
    ],
    'usage' => [
        'input_tokens' => 9,
        'output_tokens' => 1,
        'cache_creation_input_tokens' => null,
        'cache_read_input_tokens' => null,
    ]
]
// 2. iteration
[
    'type' => 'content_block_start',
    'index' => 0,
    'content_block_start' => [
        'type' => 'text',
        'text' => '',
    ]
]
// 3. iteration
[
    'type' => 'content_block_delta',
    'index' => 0,
    'delta' => [
        'type' => 'text_delta',
        'text' => 'Hello',
    ]
]
// 4. iteration
[
    'type' => 'content_block_delta',
    'index' => 0,
    'delta' => [
        'type' => 'text_delta',
        'text' => '!',
    ]
]

// ...

// last iteration
[
    'type' => 'message_delta',
    'delta' => [
        'stop_reason' => 'end_turn',
        'stop_sequence' => null,
    ],
    'usage' => [
        'output_tokens' => 12,
        'cache_creation_input_tokens' => null,
        'cache_read_input_tokens' => null,
    ]
]
```

Creates a streamed completion for structured list of input messages with a tool call.

```php
$stream = $client->messages()->createStreamed([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'What is the weather like in San Francisco?'],
    ],
    'tools' => [
        [
            'name' => 'get_weather',
            'description' => 'Get the current weather in a given location',
            'input_schema' => [
                'type' => 'object',
                'properties' => [
                    'location' => [
                        'type' => 'string',
                        'description' => 'The city and state, e.g. San Francisco, CA'
                    ],
                    'unit' => [
                        'type' => 'string',
                        'enum' => ['celsius', 'fahrenheit'],
                        'description' => 'The unit of temperature, either \"celsius\" or \"fahrenheit\"'
                    ]
                ],
                'required' => ['location']
            ]
        ]
    ]
]);

foreach($stream as $response){
    $response->toArray();
}
// 1. iteration
[
    'type' => 'message_start',
    'message' => [
        'id' => 'msg_01SX1jLtTXgtJwB2EpSRNutG',
        'type' => 'message',
        'role' => 'assistant',
        'content' => [],
        'model' => 'claude-sonnet-4-6',
        'stop_reason' => null,
        'stop_sequence' => null,
    ],
    'usage' => [
        'input_tokens' => 9,
        'output_tokens' => 1,
        'cache_creation_input_tokens' => null,
        'cache_read_input_tokens' => null,
    ]
]
// 2. iteration
[
    'type' => 'content_block_start',
    'index' => 0,
    'content_block_start' => [
        'type' => 'text',
        'text' => '',
    ]
]
// 3. iteration
[
    'type' => 'content_block_delta',
    'index' => 0,
    'delta' => [
        'type' => 'text_delta',
        'text' => 'I',
    ]
]
// 4. iteration
[
    'type' => 'content_block_delta',
    'index' => 0,
    'delta' => [
        'type' => 'text_delta',
        'text' => '\'ll help you check the current weather',
    ]
]

// ...

// 1. iteration of tool call
[
    'type' => 'content_block_start',
    'index' => 1,
    'content_block_start' => [
        'id' => 'toolu_01RDFRXpbNUGrZ1xQy443s5Q',
        'type' => 'tool_use',
        'name' => 'get_weather',
        'input' => [],
    ]
]
// 2. iteration of tool call
[
    'type' => 'content_block_delta',
    'index' => 1,
    'delta' => [
        'type' => 'input_json_delta',
        'partial_json' => '{"location',
    ]
]

// ...

// last iteration
[
    'type' => 'message_delta',
    'delta' => [
        'stop_reason' => 'end_turn',
        'stop_sequence' => null,
    ],
    'usage' => [
        'output_tokens' => 12,
        'cache_creation_input_tokens' => null,
        'cache_read_input_tokens' => null,
    ]
]
```

Creates a streamed completion with adaptive thinking. Streaming works the same way for both adaptive and `budget_tokens` thinking.

```php
$stream = $client->messages()->createStreamed([
    'model' => 'claude-opus-4-6',
    'max_tokens' => 16000,
    'thinking' => [
        'type' => 'adaptive',
    ],
    'messages' => [
        ['role' => 'user', 'content' => 'What is the greatest common divisor of 1071 and 462?'],
    ],
]);

foreach ($stream as $response) {
    $response->type; // 'content_block_start', 'content_block_delta', 'content_block_stop', ...

    // Thinking block start
    $response->content_block_start->type; // 'thinking'

    // Thinking delta
    $response->delta->type; // 'thinking_delta'
    $response->delta->thinking; // 'I need to find the GCD of 1071 and 462 using the Euclidean algorithm...'

    // Signature delta (sent before content_block_stop)
    $response->delta->type; // 'signature_delta'
    $response->delta->signature; // 'EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds...'

    // Text delta (after thinking is complete)
    $response->delta->type; // 'text_delta'
    $response->delta->text; // 'The greatest common divisor of 1071 and 462 is **21**.'
}
```

When using `'display' => 'omitted'` with streaming, no `thinking_delta` events are emitted. You'll only receive the `signature_delta` followed by text deltas, which gives a faster time-to-first-text-token.

### `Models` Resource

#### `list`

Lists the currently available models.

```php
$response = $client->models()->list();

foreach ($response->data as $model) {
    $model->id; // 'claude-sonnet-4-6'
    $model->type; // 'model'
    $model->createdAt; // '2025-05-14T00:00:00Z'
    $model->displayName; // 'Claude Sonnet 4.6'
}

$response->firstId; // 'claude-sonnet-4-6'
$response->lastId; // 'claude-haiku-4-5'
$response->hasMore; // true
```

You can paginate through models using cursor-based pagination:

```php
$response = $client->models()->list([
    'limit' => 10,
    'after_id' => 'claude-haiku-4-5',
]);
```

#### `retrieve`

Gets information about a specific model.

```php
$response = $client->models()->retrieve('claude-sonnet-4-6');

$response->id; // 'claude-sonnet-4-6'
$response->type; // 'model'
$response->createdAt; // '2025-05-14T00:00:00Z'
$response->displayName; // 'Claude Sonnet 4.6'
```

### `Message Batches` Resource

#### `create`

Creates a Message Batch. Processing may take up to 24 hours.

```php
$response = $client->batches()->create([
    'requests' => [
        [
            'custom_id' => 'request-1',
            'params' => [
                'model' => 'claude-sonnet-4-6',
                'max_tokens' => 1024,
                'messages' => [
                    ['role' => 'user', 'content' => 'What is the capital of France?'],
                ],
            ],
        ],
        [
            'custom_id' => 'request-2',
            'params' => [
                'model' => 'claude-sonnet-4-6',
                'max_tokens' => 1024,
                'messages' => [
                    ['role' => 'user', 'content' => 'What is the capital of Germany?'],
                ],
            ],
        ],
    ],
]);

$response->id; // 'msgbatch_04Rka1yCsMLGPnR7kfPdgR8x'
$response->type; // 'message_batch'
$response->processingStatus; // 'in_progress'
$response->requestCounts->processing; // 2
$response->requestCounts->succeeded; // 0
$response->createdAt; // '2025-04-01T12:00:00Z'
$response->expiresAt; // '2025-04-02T12:00:00Z'
$response->endedAt; // null
$response->resultsUrl; // null
```

#### `retrieve`

Retrieves a Message Batch. Use this to poll for completion.

```php
$response = $client->batches()->retrieve('msgbatch_04Rka1yCsMLGPnR7kfPdgR8x');

$response->processingStatus; // 'ended'
$response->requestCounts->succeeded; // 95
$response->requestCounts->errored; // 3
$response->resultsUrl; // 'https://api.anthropic.com/v1/messages/batches/msgbatch_.../results'
```

#### `list`

Lists Message Batches with cursor-based pagination.

```php
$response = $client->batches()->list(['limit' => 10]);

foreach ($response->data as $batch) {
    $batch->id; // 'msgbatch_04Rka1yCsMLGPnR7kfPdgR8x'
    $batch->processingStatus; // 'ended'
}

$response->hasMore; // true
$response->firstId; // 'msgbatch_04Rka1yCsMLGPnR7kfPdgR8x'
$response->lastId; // 'msgbatch_07V2nm5PqB3bP8szLgTmn1EG'
```

#### `cancel`

Cancels an in-progress Message Batch.

```php
$response = $client->batches()->cancel('msgbatch_04Rka1yCsMLGPnR7kfPdgR8x');

$response->processingStatus; // 'canceling'
```

#### `delete`

Deletes a Message Batch. Only completed batches can be deleted.

```php
$response = $client->batches()->delete('msgbatch_04Rka1yCsMLGPnR7kfPdgR8x');

$response->id; // 'msgbatch_04Rka1yCsMLGPnR7kfPdgR8x'
$response->type; // 'message_batch_deleted'
```

#### `results`

Streams the results of a completed Message Batch as JSONL. Each result contains the `custom_id` from the original request and a `result` with the response or error.

```php
$response = $client->batches()->results('msgbatch_04Rka1yCsMLGPnR7kfPdgR8x');

foreach ($response as $individual) {
    $individual->customId; // 'request-1'
    $individual->result->type; // 'succeeded', 'errored', 'canceled', or 'expired'

    if ($individual->result->type === 'succeeded') {
        $individual->result->message->id; // 'msg_014VwiXbi91y3JMjcpyGBHX2'
        $individual->result->message->content[0]->text; // 'Hello! How can I help you today?'
    }

    if ($individual->result->type === 'errored') {
        $individual->result->error->type; // 'invalid_request_error'
        $individual->result->error->message; // 'max_tokens: Field required'
    }
}

$response->meta(); // rate limit and request ID headers
```

### `Completions` Resource (Legacy)

#### `create`

Creates a completion for the provided prompt and parameters.

```php
$response = $client->completions()->create([
    'model' => 'claude-2.1',
    'prompt' => '\n\nHuman: Hello, Claude\n\nAssistant:',
    'max_tokens_to_sample' => 100,
    'temperature' => 0
]);

$response->type; // 'completion'
$response->id; // 'compl_01EKm5HZ9y6khqaSZjsX44fS'
$response->completion; // ' Hello! Nice to meet you.'
$response->stop_reason; // 'stop_sequence'
$response->model; // 'claude-2.1'
$response->stop; // '\n\nHuman:'
$response->log_id; // 'compl_01EKm5HZ9y6khqaSZjsX44fS'

$response->toArray(); // ['id' => 'compl_01EKm5HZ9y6khqaSZjsX44fS', ...]
```

#### `create streamed`

Creates a streamed completion for the provided prompt and parameters.

```php
$stream = $client->completions()->createStreamed([
    'model' => 'claude-2.1',
    'prompt' => 'Hi',
    'max_tokens_to_sample' => 70,
]);

foreach($stream as $response){
    $response->completion;
}
// 1. iteration => 'I'
// 2. iteration => ' am'
// 3. iteration => ' very'
// 4. iteration => ' excited'
// ...
```

## Meta Information

On messages response object you can access the meta information returned by the API via the `meta()` method.

```php
$response = $client->messages()->create([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Hello, world'],
    ],
]);

$meta = $response->meta();

$meta->requestId; // 'req_012nTzj6kLoP8vZ1SGANvcgR'

$meta->requestLimit->limit; // 3000
$meta->requestLimit->remaining; // 2999
$meta->requestLimit->reset; // '2024-05-01T13:29:17Z'

$meta->tokenLimit->limit; // 250000
$meta->tokenLimit->remaining; // 249984
$meta->tokenLimit->reset; // '2024-05-01T13:29:17Z'

$meta->inputTokenLimit->limit; // 20000
$meta->inputTokenLimit->remaining; // 19500
$meta->inputTokenLimit->reset; // '2024-05-01T13:29:17Z'

$meta->outputTokenLimit->limit; // 5000
$meta->outputTokenLimit->remaining; // 4900
$meta->outputTokenLimit->reset; // '2024-05-01T13:29:17Z'

$meta->custom; // additional non-standard headers
```

The `toArray()` method returns the meta information in the form originally returned by the API.

```php
$meta->toArray();

// [
//   'request-id' => 'req_012nTzj6kLoP8vZ1SGANvcgR',
//   'anthropic-ratelimit-requests-limit' => 3000,
//   'anthropic-ratelimit-requests-remaining' => 2999,
//   'anthropic-ratelimit-requests-reset' => '2024-05-01T13:29:17Z',
//   'anthropic-ratelimit-tokens-limit' => 250000,
//   'anthropic-ratelimit-tokens-remaining' => 249983,
//   'anthropic-ratelimit-tokens-reset' => '2024-05-01T13:29:17Z',
//   'anthropic-ratelimit-input-tokens-limit' => 20000,
//   'anthropic-ratelimit-input-tokens-remaining' => 19500,
//   'anthropic-ratelimit-input-tokens-reset' => '2024-05-01T13:29:17Z',
//   'anthropic-ratelimit-output-tokens-limit' => 5000,
//   'anthropic-ratelimit-output-tokens-remaining' => 4900,
//   'anthropic-ratelimit-output-tokens-reset' => '2024-05-01T13:29:17Z',
// ]
```

On streaming responses you can access the meta information on the reponse stream object.

```php
$stream = $client->messages()->createStreamed([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Hello, world'],
    ],
]);
    
$stream->meta(); 
```

For further details about the rates limits and what to do if you hit them visit the [Anthropic documentation](https://docs.anthropic.com/claude/reference/rate-limits).

## Error Handling

When the API returns an error, an `Anthropic\Exceptions\ErrorException` is thrown.

```php
try {
    $result = $client->messages()->create([...]);
} catch (\Anthropic\Exceptions\ErrorException $e) {
    $e->getMessage(); // 'Overloaded'
    $e->getErrorType(); // 'overloaded_error'
    $e->getStatusCode(); // 529
}
```

For rate limit errors (HTTP 429), a dedicated `Anthropic\Exceptions\RateLimitException` is thrown. Since it extends `ErrorException`, existing `catch (ErrorException $e)` blocks will continue to work. If you want to handle rate limits specifically, catch it first:

```php
try {
    $result = $client->messages()->create([...]);
} catch (\Anthropic\Exceptions\RateLimitException $e) {
    $retryAfter = $e->response->getHeaderLine('Retry-After');
} catch (\Anthropic\Exceptions\ErrorException $e) {
    // other API errors
}
```

## Troubleshooting

### Timeout

You may run into a timeout when sending requests to the API. The default timeout depends on the HTTP client used.

You can increase the timeout by configuring the HTTP client and passing in to the factory.

This example illustrates how to increase the timeout using Guzzle.

```php
Anthropic::factory()
    ->withApiKey($apiKey)
    ->withHttpClient(new \GuzzleHttp\Client(['timeout' => $timeout]))
    ->make();
```

## Testing

The package provides a fake implementation of the `Anthropic\Client` class that allows you to fake the API responses.

To test your code ensure you swap the `Anthropic\Client` class with the `Anthropic\Testing\ClientFake` class in your test case.

The fake responses are returned in the order they are provided while creating the fake client.

All responses are having a `fake()` method that allows you to easily create a response object by only providing the parameters relevant for your test case.

```php
use Anthropic\Testing\ClientFake;
use Anthropic\Responses\Completions\CreateResponse;

$client = new ClientFake([
    CreateResponse::fake([
        'completion' => 'awesome!',
    ]),
]);

$completion = $client->completions()->create([
    'model' => 'claude-2.1',
    'prompt' => '\n\nHuman: PHP is \n\nAssistant:',
    'max_tokens_to_sample' => 100,
]);

expect($completion['completion'])->toBe('awesome!');
```

In case of a streamed response you can optionally provide a resource holding the fake response data.

```php
use Anthropic\Testing\ClientFake;
use Anthropic\Responses\Messages\CreateStreamedResponse;

$client = new ClientFake([
    CreateStreamedResponse::fake(fopen('file.txt', 'r'););
]);

$completion = $client->messages()->createStreamed([
    'model' => 'claude-sonnet-4-6',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Hello!'],
    ],
]);

expect($response->getIterator()->current())
        ->type->toBe('message_start');
```

After the requests have been sent there are various methods to ensure that the expected requests were sent:

```php
// assert completion create request was sent
$client->assertSent(Completions::class, function (string $method, array $parameters): bool {
    return $method === 'create' &&
        $parameters['model'] === 'claude-2.1' &&
        $parameters['prompt'] === 'PHP is ';
});
// or
$client->completions()->assertSent(function (string $method, array $parameters): bool {
    // ...
});

// assert 2 completion create requests were sent
$client->assertSent(Completions::class, 2);

// assert no completion create requests were sent
$client->assertNotSent(Completions::class);
// or
$client->completions()->assertNotSent();

// assert no requests were sent
$client->assertNothingSent();
```

To write tests expecting the API request to fail you can provide a `Throwable` object as the response.

```php
$client = new ClientFake([
    new \Anthropic\Exceptions\ErrorException([
        'message' => 'Overloaded',
        'type' => 'overloaded_error',
    ], 529)
]);

// the `ErrorException` will be thrown
$completion = $client->completions()->create([
    'model' => 'claude-2.1',
    'prompt' => '\n\nHuman: PHP is \n\nAssistant:',
    'max_tokens_to_sample' => 100,
]);
```

---

## Table of Contents

- [Quick Start](https://mozex.dev/docs/anthropic-php/v1)
- [Support Us](https://mozex.dev/docs/anthropic-php/v1/support-us)
- [Requirements](https://mozex.dev/docs/anthropic-php/v1/requirements)
- [Changelog](https://mozex.dev/docs/anthropic-php/v1/changelog)
- [Contributing](https://mozex.dev/docs/anthropic-php/v1/contributing)
- [Questions & Issues](https://mozex.dev/docs/anthropic-php/v1/questions-and-issues)
- [About Mozex](https://mozex.dev/docs/anthropic-php/v1/about)