Claude API PHP SDK Quickstart Guide
Is there an official Claude API PHP SDK?
No. Anthropic publishes official SDKs for Python and TypeScript/JavaScript, but there is no official Claude API PHP SDK as of now. If you're building a PHP application — Laravel, Symfony, WordPress, or plain PHP — you have two realistic paths: call the Anthropic REST API directly with cURL or Guzzle, or route requests through a REST-friendly gateway that normalizes authentication and response handling for you. This guide covers both, with working code you can drop into a PHP project today.
The good news is that the Claude API is a plain HTTPS JSON API. You don't need a language-specific SDK to use it — you need correct headers, a correctly formatted request body, and a way to parse the response. PHP's built-in cURL extension or the Guzzle HTTP client handle this without any third-party package.
Setting up your PHP project
Start with Composer so you can pull in Guzzle, which makes error handling and streaming much cleaner than raw cURL.
composer require guzzlehttp/guzzle
Store your API key as an environment variable rather than hardcoding it:
export ANTHROPIC_API_KEY="your-key-here"
In Laravel, add it to .env and read it with env('ANTHROPIC_API_KEY'). In plain PHP, use getenv('ANTHROPIC_API_KEY') or a .env loader like vlucas/phpdotenv.
Calling Claude with Guzzle
Here's a minimal, working example that sends a message and prints Claude's reply:
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client();
$response = $client->post('https://api.anthropic.com/v1/messages', [
'headers' => [
'x-api-key' => getenv('ANTHROPIC_API_KEY'),
'anthropic-version' => '2023-06-01',
'content-type' => 'application/json',
],
'json' => [
'model' => 'claude-3-5-sonnet-20241022',
'max_tokens' => 1024,
'messages' => [
['role' => 'user', 'content' => 'Explain dependency injection in one paragraph.']
],
],
]);
$data = json_decode($response->getBody(), true);
echo $data['content'][0]['text'];
This works, but you'll notice a few PHP-specific pain points right away: Guzzle doesn't stream Server-Sent Events natively, error bodies need manual parsing, and every request needs the same three headers repeated. A small wrapper class fixes most of this.
A reusable Claude client class
<?php
class ClaudeClient
{
private Client $http;
private string $apiKey;
public function __construct(string $apiKey)
{
$this->apiKey = $apiKey;
$this->http = new \GuzzleHttp\Client([
'base_uri' => 'https://api.anthropic.com/v1/',
'headers' => [
'x-api-key' => $apiKey,
'anthropic-version' => '2023-06-01',
'content-type' => 'application/json',
],
]);
}
public function message(array $messages, string $model = 'claude-3-5-sonnet-20241022', int $maxTokens = 1024): array
{
$response = $this->http->post('messages', [
'json' => [
'model' => $model,
'max_tokens' => $maxTokens,
'messages' => $messages,
],
]);
return json_decode($response->getBody(), true);
}
}
$claude = new ClaudeClient(getenv('ANTHROPIC_API_KEY'));
$result = $claude->message([
['role' => 'user', 'content' => 'Summarize this changelog entry in two sentences.'],
]);
echo $result['content'][0]['text'];
This is close to how an official SDK would feel — predictable methods, shared config, typed return handling if you add DTOs. You can extend it with retry logic, tool-use payloads, and error classes as your app grows.
Handling streaming responses in PHP
Streaming is the part where the lack of an SDK hurts most. Claude's streaming API uses Server-Sent Events, and Guzzle requires 'stream' => true plus manual chunk parsing:
$response = $this->http->post('messages', [
'json' => [
'model' => 'claude-3-5-sonnet-20241022',
'max_tokens' => 1024,
'stream' => true,
'messages' => $messages,
],
'stream' => true,
]);
$body = $response->getBody();
while (!$body->eof()) {
$line = '';
while (($byte = $body->read(1)) !== "\n" && !$body->eof()) {
$line .= $byte;
}
if (str_starts_with($line, 'data:')) {
$json = json_decode(substr($line, 5), true);
if (isset($json['delta']['text'])) {
echo $json['delta']['text'];
flush();
}
}
}
This works but it's fragile — byte-by-byte reads are slow, and you're reimplementing SSE parsing that other languages get for free from official SDKs.
A simpler option: a REST layer built for this
If you don't want to maintain SSE parsing, header boilerplate, and retry logic by hand, you can put SubToAPI in front of your Claude usage. It turns your Claude access into a plain HTTPS API with a standard sub_live_... application key, so your PHP code talks to one consistent endpoint regardless of which underlying model or plan you're on. The request shape mirrors what's shown above, so the migration from direct Guzzle calls is a find-and-replace on the base URL and headers:
$response = $this->http->post('https://api.subtoapi.app/v1/messages', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('SUBTOAPI_KEY'),
'content-type' => 'application/json',
],
'json' => [
'model' => 'claude-3-5-sonnet-20241022',
'max_tokens' => 1024,
'messages' => $messages,
],
]);
You get usage metadata per request, team seats if multiple developers share the account, and streaming and tool-use support without writing your own SSE parser — see the streaming docs and tool use docs for the exact payload shapes. Plans start at €9/month for solo use, with team seats on the Team (€19/seat) and Scale (€49/seat) plans, and every account starts with a free trial — see pricing or just start at /signup.
Quickstart checklist
- Install Guzzle via Composer, or stick with cURL if you want zero dependencies.
- Store your API key in an environment variable, never in source.
- Wrap requests in a small client class so headers and base URL live in one place.
- Budget extra time for streaming — SSE parsing in PHP needs manual handling.
- If you want an SDK-like experience without building one, point your PHP app at SubToAPI's REST endpoint and follow the quickstart guide.
FAQ
Does Anthropic offer an official PHP SDK for the Claude API? No. Anthropic currently maintains official SDKs for Python and TypeScript/JavaScript only. PHP developers call the REST API directly with cURL or Guzzle, or use a community/wrapper client.
Can I use Composer packages instead of writing my own wrapper? There are a few unofficial community packages on Packagist, but none are maintained by Anthropic, so quality and update speed vary. Writing a thin Guzzle wrapper yourself, as shown above, gives you more control and no dependency risk.
How do I handle Claude's streaming responses in PHP without SSE libraries? You can read the Guzzle response body in a loop and parse data: lines manually, as shown in this guide, or use a REST layer like SubToAPI that handles the chunk parsing server-side and returns clean streamed output.