claude-code-system-prompts/system-prompts/data-claude-api-reference-php.md
2026-03-11 14:32:22 -06:00

7.1 KiB

Claude API — PHP

Note: The PHP SDK is the official Anthropic SDK for PHP. Tool runner and Agent SDK are not available. Bedrock, Vertex AI, and Foundry clients are supported.

Installation

```bash composer require "anthropic-ai/sdk" ```

Client Initialization

```php use Anthropic\Client;

// Using API key from environment variable $client = new Client(apiKey: getenv("ANTHROPIC_API_KEY")); ```

Amazon Bedrock

```php use Anthropic\Bedrock;

// Constructor is private — use the static factory. Reads AWS credentials from env. $client = Bedrock\Client::fromEnvironment(region: 'us-east-1'); ```

Google Vertex AI

```php use Anthropic\Vertex;

// Constructor is private. Parameter is `location`, not `region`. $client = Vertex\Client::fromEnvironment( location: 'us-east5', projectId: 'my-project-id', ); ```

Anthropic Foundry

```php use Anthropic\Foundry;

// Constructor is private. baseUrl or resource is required. $client = Foundry\Client::withCredentials( authToken: getenv('ANTHROPIC_FOUNDRY_AUTH_TOKEN'), baseUrl: 'https://.services.ai.azure.com/anthropic', ); ```


Basic Message Request

```php $message = $client->messages->create( model: '{{OPUS_ID}}', maxTokens: 1024, messages: [ ['role' => 'user', 'content' => 'What is the capital of France?'], ], );

// content is an array of polymorphic blocks (TextBlock, ToolUseBlock, // ThinkingBlock). Accessing ->text on content[0] without checking the block // type will throw if the first block is not a TextBlock (e.g., when extended // thinking is enabled and a ThinkingBlock comes first). Always guard: foreach ($message->content as $block) { if ($block->type === 'text') { echo $block->text; } } ```

If you only want the first text block:

```php foreach ($message->content as $block) { if ($block->type === 'text') { echo $block->text; break; } } ```


Streaming

Requires SDK v0.5.0+. v0.4.0 and earlier used a single `$params` array; calling with named parameters throws `Unknown named parameter $model`. Upgrade: `composer require "anthropic-ai/sdk:^0.6"`

```php use Anthropic\Messages\RawContentBlockDeltaEvent; use Anthropic\Messages\TextDelta;

$stream = $client->messages->createStream( model: '{{OPUS_ID}}', maxTokens: 1024, messages: [ ['role' => 'user', 'content' => 'Write a haiku'], ], );

foreach ($stream as $event) { if ($event instanceof RawContentBlockDeltaEvent && $event->delta instanceof TextDelta) { echo $event->delta->text; } } ```


Tool Use (Manual Loop)

Tools are passed as arrays. The SDK uses camelCase keys (`inputSchema`, `toolUseID`, `stopReason`) and auto-maps to the API's snake_case on the wire — since v0.5.0. See shared tool use concepts for the loop pattern.

```php use Anthropic\Messages\ToolUseBlock;

$tools = [ [ 'name' => 'get_weather', 'description' => 'Get the current weather in a given location', 'inputSchema' => [ // camelCase, not input_schema 'type' => 'object', 'properties' => [ 'location' => ['type' => 'string', 'description' => 'City and state'], ], 'required' => ['location'], ], ], ];

$messages = ;

$response = $client->messages->create( model: '{{OPUS_ID}}', maxTokens: 1024, tools: $tools, messages: $messages, );

while ($response->stopReason === 'tool_use') { // camelCase property $toolResults = []; foreach ($response->content as $block) { if ($block instanceof ToolUseBlock) { // $block->name : string — tool name to dispatch on // $block->input : array<string,mixed> — parsed JSON input // $block->id : string — pass back as toolUseID $result = executeYourTool($block->name, $block->input); $toolResults[] = [ 'type' => 'tool_result', 'toolUseID' => $block->id, // camelCase, not tool_use_id 'content' => $result, ]; } }

// Append assistant turn + user turn with tool results
$messages[] = ['role' => 'assistant', 'content' => $response->content];
$messages[] = ['role' => 'user', 'content' => $toolResults];

$response = $client->messages->create(
    model: '{{OPUS_ID}}',
    maxTokens: 1024,
    tools: $tools,
    messages: $messages,
);

}

// Final text response foreach ($response->content as $block) { if ($block->type === 'text') { echo $block->text; } } ```

`$block->type === 'tool_use'` also works; `instanceof ToolUseBlock` narrows for PHPStan.


Extended Thinking

Adaptive thinking is the recommended mode for Claude 4.6+ models. Claude decides dynamically when and how much to think.

```php use Anthropic\Messages\ThinkingBlock;

$message = $client->messages->create( model: '{{OPUS_ID}}', maxTokens: 16000, thinking: ['type' => 'adaptive'], messages: [ ['role' => 'user', 'content' => 'Solve: 27 * 453'], ], );

// ThinkingBlock(s) precede TextBlock in content foreach ($message->content as $block) { if ($block instanceof ThinkingBlock) { echo "Thinking:\n{$block->thinking}\n\n"; // $block->signature is an opaque string — preserve verbatim if // passing thinking blocks back in multi-turn conversations } elseif ($block->type === 'text') { echo "Answer: {$block->text}\n"; } } ```

Deprecated: `['type' => 'enabled', 'budgetTokens' => N]` (fixed-budget extended thinking) still works on Claude 4.6 but is deprecated. Use adaptive thinking above.

`$block->type === 'thinking'` also works for the check; `instanceof` narrows for PHPStan.


Beta Features & Server-Side Tools

`betas:` is NOT a param on `$client->messages->create()` — it only exists on the beta namespace. Use it for features that need an explicit opt-in header:

```php use Anthropic\Beta\Messages\BetaRequestMCPServerURLDefinition;

$response = $client->beta->messages->create( model: '{{OPUS_ID}}', maxTokens: 1024, mcpServers: [ BetaRequestMCPServerURLDefinition::with( name: 'my-server', url: 'https://example.com/mcp', ), ], betas: ['mcp-client-2025-11-20'], // only valid on ->beta->messages messages: , ); ```

Server-side tools (bash, web_search, text_editor, code_execution) are GA and work on both paths — `Anthropic\Messages\ToolBash20250124` / `WebSearchTool20260209` / `ToolTextEditor20250728` / `CodeExecutionTool20260120` for non-beta, `Anthropic\Beta\Messages\BetaToolBash20250124` / `BetaWebSearchTool20260209` / `BetaToolTextEditor20250728` / `BetaCodeExecutionTool20260120` for beta. No `betas:` header needed for these.