Working PHP code for calling the Claude API using cURL and Guzzle. No official PHP SDK needed — these copy-paste examples work with Laravel, WordPress, and plain PHP scripts.
PHP has no official Anthropic SDK, so the standard approach is to call the REST API via cURL or Guzzle. These examples work in plain PHP 8+, Laravel, Symfony, and WordPress.
<?php
function claude(string $prompt, string $model = "claude-sonnet-4-6", int $maxTokens = 1024): string {
$ch = curl_init("https://api.anthropic.com/v1/messages");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"x-api-key: " . getenv("ANTHROPIC_API_KEY"),
"anthropic-version: 2023-06-01",
"content-type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"model" => $model,
"max_tokens" => $maxTokens,
"messages" => [["role" => "user", "content" => $prompt]],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true)["content"][0]["text"];
}
echo claude("Explain PHP 8 fibers in one paragraph.");
$body = json_encode([
"model" => "claude-sonnet-4-6",
"max_tokens" => 512,
"system" => "You are a concise PHP expert. Respond in bullet points.",
"messages" => [["role" => "user", "content" => "What is the difference between abstract classes and interfaces in PHP?"]],
]);
<?php
class ClaudeClient {
private string $apiKey;
private string $model;
const BASE_URL = "https://api.anthropic.com/v1/messages";
public function __construct(string $apiKey = "", string $model = "claude-sonnet-4-6") {
$this->apiKey = $apiKey ?: getenv("ANTHROPIC_API_KEY");
$this->model = $model;
}
public function chat(array $messages, ?string $system = null, int $maxTokens = 1024): string {
$body = ["model" => $this->model, "max_tokens" => $maxTokens, "messages" => $messages];
if ($system) $body["system"] = $system;
$ch = curl_init(self::BASE_URL);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => $this->headers(),
CURLOPT_POSTFIELDS => json_encode($body),
]);
$res = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code !== 200) throw new RuntimeException("Claude API error $code: $res");
return json_decode($res, true)["content"][0]["text"];
}
private function headers(): array {
return [
"x-api-key: " . $this->apiKey,
"anthropic-version: 2023-06-01",
"content-type: application/json",
];
}
}
$client = new ClaudeClient();
echo $client->chat([["role" => "user", "content" => "Write a PHP function to sanitize user input."]]);
<?php
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
$body = json_encode([
"model" => "claude-sonnet-4-6",
"max_tokens" => 1024,
"stream" => true,
"messages" => [["role" => "user", "content" => "Write a tutorial on PHP 8 match expressions."]],
]);
$buffer = "";
$ch = curl_init("https://api.anthropic.com/v1/messages");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"x-api-key: " . getenv("ANTHROPIC_API_KEY"),
"anthropic-version: 2023-06-01",
"content-type: application/json",
],
CURLOPT_POSTFIELDS => $body,
CURLOPT_WRITEFUNCTION => function ($ch, $chunk) use (&$buffer) {
$buffer .= $chunk;
while (($pos = strpos($buffer, "
")) !== false) {
$line = substr($buffer, 0, $pos);
$buffer = substr($buffer, $pos + 1);
if (!str_starts_with($line, "data: ")) continue;
$data = json_decode(substr($line, 6), true);
if ($data["type"] ?? "" === "content_block_delta") {
echo "data: " . json_encode(["text" => $data["delta"]["text"]]) . "
";
ob_flush(); flush();
}
}
return strlen($chunk);
},
]);
curl_exec($ch);
curl_close($ch);
// composer require guzzlehttp/guzzle
use GuzzleHttpClient;
$http = new Client(["base_uri" => "https://api.anthropic.com"]);
$res = $http->post("/v1/messages", [
"headers" => [
"x-api-key" => env("ANTHROPIC_API_KEY"),
"anthropic-version" => "2023-06-01",
],
"json" => [
"model" => "claude-sonnet-4-6",
"max_tokens" => 1024,
"messages" => [["role" => "user", "content" => "Explain Laravel service containers."]],
],
]);
$reply = json_decode($res->getBody(), true)["content"][0]["text"];
// wp-config.php
define('ANTHROPIC_API_KEY', 'sk-ant-...');
// functions.php or plugin
function claude_wp(string $prompt): string {
$response = wp_remote_post("https://api.anthropic.com/v1/messages", [
"headers" => [
"x-api-key" => ANTHROPIC_API_KEY,
"anthropic-version" => "2023-06-01",
"content-type" => "application/json",
],
"body" => json_encode([
"model" => "claude-sonnet-4-6",
"max_tokens" => 512,
"messages" => [["role" => "user", "content" => $prompt]],
]),
"timeout" => 30,
]);
return json_decode(wp_remote_retrieve_body($response), true)["content"][0]["text"];
}
| Scenario | Recommendation | Reason |
|---|---|---|
| Plain PHP / no Composer | cURL | Built-in, zero dependencies |
| Laravel / Symfony project | Guzzle or Http facade | Already a dependency; cleaner async support |
| WordPress plugin | wp_remote_post() | Respects WordPress HTTP filters and caching |
| Streaming to browser | cURL WRITEFUNCTION | Lowest overhead for chunked writes |
| Retry / concurrency | Guzzle + RetryMiddleware | Built-in middleware stack |
To estimate costs for your PHP application, use the Claude API Cost Calculator. For model pricing details, see the Anthropic API pricing guide.