OpenAI PHP SDK: Complete Guide with Code Examples (2026)

The openai-php/client is the official PHP library for the OpenAI API. It covers chat completions, streaming, embeddings, image generation, audio transcription, and more. This guide walks through every major feature with complete, runnable code examples.

If you’re using Laravel, see How to Integrate OpenAI API with Laravel for a framework-specific guide. For a basic PHP setup, see OpenAI PHP Tutorial.


Installation

composer require openai-php/client

Requirements: PHP 8.1+, Composer. The package requires the php-http/discovery package for HTTP transport, which is installed automatically.


Initialization

<?php

require 'vendor/autoload.php';

$client = OpenAI::client(getenv('OPENAI_API_KEY'));

Set your API key as an environment variable:

export OPENAI_API_KEY=sk-proj-...

Chat Completions

The most common use case — send messages and get a response:

$response = $client->chat()->create([
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'system', 'content' => 'You are a helpful assistant.'],
        ['role' => 'user',   'content' => 'What is the capital of France?'],
    ],
]);

echo $response->choices[0]->message->content;
// Paris

Multi-Turn Conversations

Build a conversation by appending each exchange to the messages array:

$messages = [
    ['role' => 'system', 'content' => 'You are a helpful assistant.'],
];

function chat(array &$messages, string $input, $client): string
{
    $messages[] = ['role' => 'user', 'content' => $input];

    $response = $client->chat()->create([
        'model' => 'gpt-4o-mini',
        'messages' => $messages,
    ]);

    $reply = $response->choices[0]->message->content;
    $messages[] = ['role' => 'assistant', 'content' => $reply];

    return $reply;
}

echo chat($messages, 'My name is Alex.', $client);  // Nice to meet you, Alex!
echo chat($messages, 'What is my name?', $client);  // Your name is Alex.

Streaming Responses

Stream tokens as they are generated — ideal for chat UIs:

$stream = $client->chat()->createStreamed([
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'user', 'content' => 'Write a short poem about PHP.'],
    ],
]);

foreach ($stream as $response) {
    $delta = $response->choices[0]->delta->content;
    if ($delta !== null) {
        echo $delta;
        ob_flush();
        flush();
    }
}

For a web-based streaming UI with SSE, see How to Build an AI Chatbot with PHP.


Function Calling / Tool Use

Define tools that the model can call:

$response = $client->chat()->create([
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'user', 'content' => "What's the weather in Kyiv?"],
    ],
    'tools' => [
        [
            'type' => 'function',
            'function' => [
                'name' => 'get_weather',
                'description' => 'Get current weather for a city',
                'parameters' => [
                    'type' => 'object',
                    'properties' => [
                        'city' => ['type' => 'string', 'description' => 'City name'],
                    ],
                    'required' => ['city'],
                ],
            ],
        ],
    ],
    'tool_choice' => 'auto',
]);

$message = $response->choices[0]->message;

if ($message->toolCalls) {
    foreach ($message->toolCalls as $toolCall) {
        $name = $toolCall->function->name;
        $args = json_decode($toolCall->function->arguments, true);
        // Execute your function here: call_weather_api($args['city'])
        echo "Model wants to call: $name with args: " . json_encode($args);
    }
}

Text Embeddings

Convert text into vectors for semantic search or RAG:

$response = $client->embeddings()->create([
    'model' => 'text-embedding-3-small',
    'input' => 'Laravel is a PHP framework for web artisans.',
]);

$vector = $response->embeddings[0]->embedding;
// 1536-dimensional float array

// Batch embeddings
$response = $client->embeddings()->create([
    'model' => 'text-embedding-3-small',
    'input' => ['First text', 'Second text', 'Third text'],
]);

foreach ($response->embeddings as $embedding) {
    // $embedding->embedding — vector
    // $embedding->index    — position in input array
}

Image Generation (DALL·E)

// Generate image
$response = $client->images()->create([
    'model'   => 'dall-e-3',
    'prompt'  => 'A futuristic PHP elephant mascot',
    'n'       => 1,
    'size'    => '1024x1024',
    'quality' => 'standard',
]);

$imageUrl = $response->data[0]->url;
echo $imageUrl; // https://oaidalleapiprodscus.blob.core.windows.net/...

// Edit an existing image (requires mask)
$response = $client->images()->edit([
    'image'  => fopen('original.png', 'r'),
    'mask'   => fopen('mask.png', 'r'),
    'prompt' => 'Add a rainbow in the background',
    'n'      => 1,
    'size'   => '1024x1024',
]);

Audio Transcription (Whisper)

$response = $client->audio()->transcribe([
    'model' => 'whisper-1',
    'file'  => fopen('audio.mp3', 'r'),
]);

echo $response->text;
// The transcribed text from the audio file

// Translate non-English audio to English
$response = $client->audio()->translate([
    'model' => 'whisper-1',
    'file'  => fopen('french_audio.mp3', 'r'),
]);

Moderation

Check if content violates OpenAI usage policies:

$response = $client->moderations()->create([
    'input' => $userMessage,
]);

$result = $response->results[0];

if ($result->flagged) {
    $categories = array_filter((array) $result->categories);
    echo "Flagged categories: " . implode(', ', array_keys($categories));
} else {
    echo "Content is safe";
}

Error Handling

Always handle API errors in production:

use OpenAI\Exceptions\ErrorException;
use OpenAI\Exceptions\TransporterException;
use OpenAI\Exceptions\UnserializableResponse;

try {
    $response = $client->chat()->create([
        'model'    => 'gpt-4o-mini',
        'messages' => [['role' => 'user', 'content' => $input]],
    ]);
    return $response->choices[0]->message->content;

} catch (ErrorException $e) {
    // 400 Bad Request, 401 Unauthorized, 429 Rate Limit, 500 Server Error
    $code = $e->getCode();
    if ($code === 429) {
        // Rate limited — implement exponential backoff
        sleep(2);
        // retry...
    }
    throw new RuntimeException("OpenAI error [{$code}]: " . $e->getMessage());

} catch (TransporterException $e) {
    // Network timeout, DNS failure, etc.
    throw new RuntimeException("Network error: " . $e->getMessage());

} catch (UnserializableResponse $e) {
    // Unexpected response format
    throw new RuntimeException("Invalid response: " . $e->getMessage());
}

Configuration Options

Customise the client with a factory:

$client = OpenAI::factory()
    ->withApiKey(getenv('OPENAI_API_KEY'))
    ->withOrganization('org-...')       // optional
    ->withBaseUri('https://api.openai.com/v1')
    ->withHttpClient(new \GuzzleHttp\Client(['timeout' => 30]))
    ->withHttpHeader('X-Custom-Header', 'value')
    ->make();

Listing Models

$models = $client->models()->list();

foreach ($models->data as $model) {
    echo $model->id . "\n";
}
// gpt-4o, gpt-4o-mini, gpt-3.5-turbo, text-embedding-3-small, ...

// Get a single model
$model = $client->models()->retrieve('gpt-4o-mini');
echo $model->ownedBy; // openai

Summary

  • composer require openai-php/client — install the SDK
  • Chat: $client->chat()->create() — supports system/user/assistant roles
  • Streaming: $client->chat()->createStreamed() — iterate over token chunks
  • Embeddings: $client->embeddings()->create() — returns float vectors
  • Images: $client->images()->create() — DALL·E 3 generation
  • Audio: $client->audio()->transcribe() — Whisper transcription
  • Errors: catch ErrorException, TransporterException, UnserializableResponse

Subscribe to my newsletter — practical guides on Claude API, AI agents, RAG, and automation.

Subscribe