← Blog

Claude API PHP Integration: Code Sample & Guide

2026-10-24 · 4 min read · SubToAPI Team

If you're searching for a Claude API PHP integration code sample, you've probably noticed something: Anthropic doesn't ship an official PHP SDK. There's no composer require anthropic/claude package maintained by the vendor, unlike Python or TypeScript. That doesn't mean PHP integration is hard — it means you need to talk to the HTTP API directly using cURL or Guzzle.

This article gives you working PHP code to send requests to Claude, handle responses, and stream output, plus a simpler alternative if you want a stable REST endpoint with a standard API key instead of managing Anthropic's native auth headers and versioning yourself.

Why PHP integration feels harder than it should

Claude's native API expects specific headers (x-api-key, anthropic-version), a JSON body shaped around a messages array, and a response format that nests content blocks rather than returning a flat string. None of this is PHP-specific — every language has to deal with it — but without an official SDK, PHP developers end up writing and maintaining their own thin client, which is where bugs and version drift creep in.

Two realistic paths:

  1. Call the native API directly with cURL or Guzzle and maintain the header/version logic yourself.
  2. Use a proxy service like SubToAPI that turns your existing Claude access into a plain HTTPS API with a standard Authorization: Bearer key, so your PHP code looks like any other REST integration.

Both are shown below.

PHP integration with cURL (direct to Claude)

Here's a minimal, working example using PHP's built-in cURL extension:

<?php

$apiKey = getenv('ANTHROPIC_API_KEY');

$payload = [
    'model' => 'claude-3-5-sonnet-20241022',
    'max_tokens' => 1024,
    'messages' => [
        ['role' => 'user', 'content' => 'Summarize this changelog in two sentences.']
    ],
];

$ch = curl_init('https://api.anthropic.com/v1/messages');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_HTTPHEADER => [
        'content-type: application/json',
        'x-api-key: ' . $apiKey,
        'anthropic-version: 2023-06-01',
    ],
]);

$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status !== 200) {
    throw new RuntimeException("Claude API error ({$status}): {$response}");
}

$data = json_decode($response, true);
echo $data['content'][0]['text'];

Things that trip people up the first time:

PHP integration with Guzzle

If your project already uses Guzzle (most Laravel and Symfony apps do), the same call looks like this:

use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.anthropic.com']);

$response = $client->post('/v1/messages', [
    'headers' => [
        'content-type' => 'application/json',
        'x-api-key' => getenv('ANTHROPIC_API_KEY'),
        'anthropic-version' => '2023-06-01',
    ],
    'json' => [
        'model' => 'claude-3-5-sonnet-20241022',
        'max_tokens' => 1024,
        'messages' => [
            ['role' => 'user', 'content' => 'Summarize this changelog in two sentences.']
        ],
    ],
]);

$data = json_decode($response->getBody(), true);
echo $data['content'][0]['text'];

Guzzle handles connection pooling and retries better than raw cURL, which matters once you're making Claude calls on every request in a production app rather than a one-off script.

A simpler route: one HTTPS API key, no native header handling

If you'd rather not maintain version headers, retry logic, and streaming parsers yourself, SubToAPI wraps Claude access in a conventional HTTPS API with sub_live_... keys and standard Authorization: Bearer auth — the same pattern PHP developers already use for Stripe, Twilio, or any other REST vendor.

<?php

$apiKey = getenv('SUBTOAPI_KEY');

$ch = curl_init('https://api.subtoapi.app/v1/messages');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode([
        'model' => 'claude-3-5-sonnet-20241022',
        'max_tokens' => 1024,
        'messages' => [
            ['role' => 'user', 'content' => 'Summarize this changelog in two sentences.']
        ],
    ]),
    CURLOPT_HTTPHEADER => [
        'content-type: application/json',
        'Authorization: Bearer ' . $apiKey,
    ],
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);
echo $data['content'][0]['text'];

No anthropic-version header, no separate x-api-key scheme — just a bearer token like any other API your team already integrates with. See /docs/quickstart and /docs/messages for the full request/response reference.

Streaming and tool use from PHP

Streaming in raw PHP cURL requires manually consuming SSE chunks with CURLOPT_WRITEFUNCTION, buffering partial JSON lines, and parsing data: events yourself — doable, but fiddly. SubToAPI's streaming endpoint follows the same SSE contract, documented at /docs/streaming, so whatever parsing code you write works regardless of which backend you point it at.

If your PHP app needs Claude to call functions (database lookups, internal APIs, calculators), tool use works the same way over HTTP — you define a tool schema in the request and handle the tool_use block in the response. Details are in /docs/tools.

Choosing between direct integration and a proxy

Direct integration makes sense if you're prototyping or have very simple, low-volume usage. A proxy like SubToAPI starts paying off once you need:

Plans start at Solo (€9), Team (€19/seat), and Scale (€49/seat), with a free trial at /signup — see /pricing for the full breakdown.

Questions

Is there an official PHP SDK for the Claude API? No. Anthropic maintains official SDKs for Python and TypeScript/JavaScript; PHP integrations are built on cURL or Guzzle calls to the HTTP API directly, or via a proxy service with a standard REST contract.

Can I use Laravel's HTTP client instead of raw cURL? Yes — Laravel's Http::withHeaders()->post() wraps Guzzle, so the same headers and JSON payload shown above work unchanged inside any Laravel controller or job.

Why would I use SubToAPI instead of calling Claude directly from PHP? It replaces Anthropic's native auth headers and version strings with a single bearer key and gives you usage tracking and team billing out of the box, which removes code you'd otherwise have to write and maintain yourself.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →