Claude API в PHP: Guzzle и curl для обращения к Zukko
Как обращаться к Claude и GPT из PHP: Guzzle, встроенный curl, разбор ошибок, стриминг и интеграция в Laravel.
4 мин · · разработка
PHP по-прежнему держит большую часть сайтов и CRM-доработок, и подключить к ним Claude API несложно: это обычный HTTPS-запрос с JSON. Ниже — рабочие примеры для Zukko через Guzzle и через встроенные функции curl_*, обработка ошибок, потоковый ответ и вариант для Laravel. Запросы идут в OpenAI-совместимый эндпоинт https://api.zukko.pro/v1/chat/completions, поэтому тот же код подходит для Claude, GPT и GLM.
Способ 1: Guzzle
Guzzle — самый распространённый HTTP-клиент в PHP, он уже есть в Laravel и многих фреймворках.
composer require guzzlehttp/guzzle<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => 'https://api.zukko.pro/v1/',
'timeout' => 60,
]);
$response = $client->post('chat/completions', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('ZUKKO_API_KEY'),
],Опция json сама сериализует массив и ставит заголовок Content-Type: application/json. Обратите внимание на base_uri: он заканчивается на /, а путь chat/completions — без ведущего слэша. Иначе Guzzle по правилам разрешения URL отбросит /v1 и запрос уйдёт не туда. По умолчанию Guzzle бросает исключение на ответах 4xx и 5xx — это используем ниже.
Способ 2: встроенный curl
Если ставить зависимости нельзя, хватит расширения curl, которое включено почти на любом хостинге:
<?php
$apiKey = getenv('ZUKKO_API_KEY');
$payload = json_encode([
'model' => 'claude-sonnet-5',
'max_tokens' => 500,
'messages' => [
['role' => 'user', 'content' => 'Объясни в трёх предложениях, что такое REST API'],
],
], JSON_UNESCAPED_UNICODE);
$ch = curl_init('https://api.zukko.pro/v1/chat/completions');
curl_setopt_array($ch, [curl_exec возвращает false при сетевой ошибке (DNS, таймаут, TLS) — это нужно проверять отдельно от HTTP-статуса. Текст ошибки API лежит в поле error.message.
Обработка ошибок в Guzzle
Коды ответа подсказывают, что делать: 401 — неверный ключ, 402 — закончился баланс, 403 — модель не разрешена для ключа, 413 — слишком большой запрос, 429 — слишком часто, 503 — провайдер модели временно недоступен. Повторять имеет смысл только 429 и 503.
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Exception\ConnectException;
function askModel(Client $client, string $prompt, int $attempts = 3): string
{
for ($i = 1; $i <= $attempts; $i++) {
try {
$response = $client->post('chat/completions', [
'headers' => ['Authorization' => 'Bearer ' . getenv('ZUKKO_API_KEY')],
'json' => [BadResponseException — общий родитель ClientException (4xx) и ServerException (5xx), поэтому один блок ловит обе группы. ConnectException — это сетевые сбои, когда ответа от сервера нет вовсе.
Стриминг ответа
Чтобы показывать текст по мере генерации, передайте "stream": true в теле запроса и опцию Guzzle 'stream' => true, чтобы он не ждал конца ответа. Сервер присылает строки data: {...} и в конце data: [DONE]; последний чанк может прийти с пустым choices.
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.zukko.pro/v1/', 'timeout' => 120]);
$response = $client->post('chat/completions', [
'headers' => ['Authorization' => 'Bearer ' . getenv('ZUKKO_API_KEY')],
'json' => [
'model' => 'claude-sonnet-5',
'stream' => true,
'messages' => [['role' => 'user', 'content' => 'Напиши короткое стихотворение про кота']],
],Куски сети не совпадают с границами строк, поэтому данные копятся в $buffer и разбираются только целыми строками. Если скрипт отдаёт поток в браузер через PHP-FPM и nginx, проверьте, что буферизация вывода отключена, иначе текст придёт одним куском в конце.
Интеграция в Laravel
Ключ кладём в .env:
ZUKKO_API_KEY=fetch_ваш_ключ
ZUKKO_API_URL=https://api.zukko.pro/v1Дополняем config/services.php:
'zukko' => [
'key' => env('ZUKKO_API_KEY'),
'url' => env('ZUKKO_API_URL', 'https://api.zukko.pro/v1'),
],Контроллер на встроенном HTTP-клиенте Laravel (он работает поверх Guzzle):
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class ChatController extends Controller
{
public function chat(Request $request)
{
$validated = $request->validate(['message' => 'required|string|max:4000']);
$response = Http::withToken(config('services.zukko.key'))Ключ остаётся на сервере, а фронтенд получает только текст ответа. Не возвращайте клиенту весь ответ API целиком — в нём служебные поля, которые браузеру не нужны.
Сколько это стоит
Цена в Zukko считается по токенам. Пример: 1000 запросов, в каждом около 500 входных и 300 выходных токенов, всего 0,5M входных и 0,3M выходных:
| Модель | Цена вход/выход за 1M | Расчёт | Итого |
|---|---|---|---|
claude-sonnet-5 | $0.3 / $0.3 | 0,5 × 0,3 + 0,3 × 0,3 | $0.24 |
gpt-5.6-luna | $0.1 / $0.1 | 0,5 × 0,1 + 0,3 × 0,1 | $0.08 |
glm-5.3-flash | $0.04 / $0.04 | 0,5 × 0,04 + 0,3 × 0,04 | $0.032 |
Реальное число токенов смотрите в поле usage каждого ответа. Какая модель справится с вашей задачей, проверьте на своих данных: прогоните одинаковый набор запросов через две-три модели и сравните.
Частые вопросы
Где взять API-ключ?
Создайте ключ в кабинете. Полный ключ показывается один раз при создании — сразу сохраните его в .env или переменную окружения. Подробнее о заголовке авторизации — в разделе Authentication.
Как ограничить время ожидания?
В Guzzle — опции timeout (весь запрос) и connect_timeout (установка соединения). В curl — CURLOPT_TIMEOUT и CURLOPT_CONNECTTIMEOUT. В Laravel — метод timeout() у HTTP-клиента. Для длинных ответов ставьте 60–120 секунд или используйте стриминг.
Ошибка «SSL certificate problem»?
Значит, PHP не находит актуальный набор корневых сертификатов. Обновите пакет ca-certificates в системе или укажите путь к файлу сертификатов в php.ini (параметры curl.cainfo и openssl.cafile). Отключать проверку сертификата не стоит даже на тестовом сервере — так проще всего утащить ключ.
Можно ли использовать другие модели?
Да, поменяйте поле model: claude-opus-5-5, gpt-5.6-sol, gpt-5.6-luna, glm-5.3, glm-5.3-flash. Актуальный список — GET https://api.zukko.pro/v1/models или страница «Модели» в кабинете, справка — в описании Chat Completions.
zukko
Платите в 25×
меньше
за Claude Code & ChatGPT
Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.
Похожие статьи
- Промпт-инъекция: что это и как защитить бота и агентаОбъясняем, как работает промпт-инъекция через пользовательский ввод и чужие документы, и какие меры снижают ущерб: изоляция данных, права инструментов, лимиты ключа.
- Свой прокси к нейросети на Node.js: не показывать API-ключ во фронтендеНебольшой сервер на Express между вашим фронтендом и API нейросети: ключ остаётся на сервере, а модели, длина запроса и частота ограничены.
- DeepSeek API на Python: запросы, стриминг, JSON и обработка ошибокГотовый код для DeepSeek V4.1 Flash и V4 Pro на OpenAI SDK: запрос, стриминг, разбор JSON и аккуратная обработка ошибок.
- Промпт-инжиниринг: примеры и 12 готовых шаблонов для работыДвенадцать шаблонов промптов для рабочих задач: что в них написано, почему именно так и сколько стоит один вызов по API.