n4nAI

The openai-php client library: setup and usage

A hands-on tutorial for openai-php client library setup: install via Composer, configure API keys, make chat calls, stream, and use with Laravel.

n4n Team3 min read585 words

Audio narration

Coming soon — every post will get a voice note here.

The openai-php client library setup is straightforward with Composer, but a few configuration details trip up first-time users. This tutorial builds a small CLI script that talks to the OpenAI Chat Completions API, then shows how to adapt the same client for Laravel and any OpenAI-compatible gateway.

Prerequisites

Confirm your environment before writing code:

  • PHP 8.1 or newer (the client uses enums, readonly classes, and union types)
  • Composer 2.x installed globally or locally
  • An API key from OpenAI, or a key for an OpenAI-compatible service
  • The curl extension enabled (PSR-18 clients typically use it)
  • Basic comfort with PSR-4 autoloading and a terminal

For a plain PHP project, create a working directory and run composer init -n to generate a baseline composer.json. Laravel users already meet the PHP and Composer requirements.

Install the package

Run the require command in your project root:

composer require openai-php/client

Composer resolves the latest stable openai-php/client (v0.9.x as of writing) and pulls in php-http/discovery plus a PSR-18 HTTP client implementation. After the install finishes, inspect the lock file:

composer show openai-php/client

Expected output includes a line like versions: * v0.9.0 and a list of dependencies. Your composer.json now contains:

{
    "require": {
        "openai-php/client": "^0.9",
        "php": "^8.1"
    }
}

Verify the autoloader exists:

test -f vendor/autoload.php && echo "autoloader present"

Output: autoloader present.

Configure the client

The client is constructed through the OpenAI\OpenAI factory. The minimal form takes an API key string:

<?php

require __DIR__ . '/vendor/autoload.php';

use OpenAI\OpenAI;

$apiKey = getenv('OPENAI_API_KEY');
if ($apiKey === false) {
    fwrite(STDERR, "OPENAI_API_KEY not set\n");
    exit(1);
}

$client = OpenAI::client($apiKey);

echo "Client ready\n";

Run it after exporting your key:

export OPENAI_API_KEY=sk-...
php script.php

Expected output:

Client ready

The factory also accepts an associative options array for baseUri, timeout, headers, organization, and logger. For example, to set a 10-second timeout:

$client = OpenAI::client($apiKey, timeout: 10);

First chat completion

Make a non-streaming call to gpt-4o-mini. The method chain mirrors the REST path: chat()->create().

<?php

require __DIR__ . '/vendor/autoload.php';

use OpenAI\OpenAI;

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

$response = $client->chat()->create([
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'system', 'content' => 'You are a terse PHP expert.'],
        ['role' => 'user', 'content' => 'What is the difference between === and == in PHP?'],
    ],
    'temperature' => 0.2,
]);

echo $response->choices[0]->message->content . "\n";

Expected output (abridged):

=== checks both value and type; == checks only value after type juggling. Use === to avoid surprises.

The returned object is a typed response struct. Dump the usage field to see token accounting:

printf(
    "Tokens: prompt=%d completion=%d total=%d\n",
    $response->usage->promptTokens,
    $response->usage->completionTokens,
    $response->usage->totalTokens
);

A sample print:

Tokens: prompt=28 completion=19 total=47

Streaming responses

For interactive apps, stream tokens as they arrive. The createStreamed() method returns a Generator:

<?php

require __DIR__ . '/vendor/autoload.php';

use OpenAI\OpenAI;

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

$stream = $client->chat()->createStreamed([
    'model' => 'gpt-4o-mini',
    'messages' => [
        ['role' => 'user', 'content' => 'List three PHP array functions.'],
    ],
    'temperature' => 0.5,
]);

foreach ($stream as $chunk) {
    $delta = $chunk->choices[0]->delta->content ?? '';
    echo $delta;
    flush();
}
echo "\n";

You will see incremental output printed without waiting for the full response. Each $chunk has a ->choices[0]->finishReason that becomes "stop" on the final packet.

Integrate with Laravel

In Laravel, bind the client as a singleton in a service provider. Store the key in .env and config/services.php:

# .env
OPENAI_API_KEY=sk-...
// config/services.php
return [
    // ...
    'openai' => [
        'key' => env('OPENAI_API_KEY'),
    ],
];

Create app/Providers/OpenAIProvider.php:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use OpenAI\Client;
use OpenAI\OpenAI;

class OpenAIProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Client::class, function () {
            return OpenAI::client(config('services.openai.key'));
        });
    }
}

Register it in bootstrap/providers.php (Laravel 11) or config/app.php (older). Then inject the client into a controller:

<?php

namespace App\Http\Controllers;

use OpenAI\Client;
use Illuminate\Http\Request;

class AskController extends Controller
{
    public function __invoke(Request $request, Client $client)
    {
        $reply = $client->chat()->create([
            'model' => 'gpt-4o-mini',
            'messages' => [['role' => 'user', 'content' => $request->input('q')]],
        ]);

        return response()->json(['answer' => $reply->choices[0]->message->content]);
    }
}

This keeps the openai-php client library setup isolated from business logic and makes unit testing trivial with a mocked Client.

Target an OpenAI-compatible gateway

The client speaks the OpenAI REST contract, so you can point it at any compatible endpoint by passing baseUri. For example, n4n.ai provides a single OpenAI-compatible endpoint that fronts 240+ models and automatically falls back when a provider is rate-limited. Set the base URI and use the same method calls:

<?php

require __DIR__ . '/vendor/autoload.php';

use OpenAI\OpenAI;

$client = OpenAI::client(
    apiKey: getenv('N4N_API_KEY'),
    baseUri: 'https://api.n4n.ai/v1',
);

$response = $client->chat()->create([
    'model' => 'anthropic/claude-3.5-sonnet',
    'messages' => [['role' => 'user', 'content' => 'Ping']],
    'temperature' => 0.0,
]);

echo $response->choices[0]->message->content . "\n";

Some gateways, including n4n.ai, honor client routing directives and forward provider cache-control hints, so you can attach cache_control metadata in messages when the upstream model supports it. The client passes extra keys through untouched.

Handle errors and retries

Network failures and rate limits happen. Catch OpenAI\Exceptions\ErrorException at the boundary:

<?php

require __DIR__ . '/vendor/autoload.php';

use OpenAI\OpenAI;
use OpenAI\Exceptions\ErrorException;

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

try {
    $response = $client->chat()->create([
        'model' => 'gpt-4o-mini',
        'messages' => [['role' => 'user', 'content' => 'Hello']],
    ]);
} catch (ErrorException $e) {
    fwrite(STDERR, sprintf("API error %s: %s\n", $e->getCode(), $e->getMessage()));
    exit(1);
}

echo $response->choices[0]->message->content . "\n";

The library does not retry by default. For transient 429s, wrap the call in a short backoff loop, or supply a PSR-18 client with retry middleware via the httpClient option.

Inspect requests during development

To see the raw payload, swap in a PSR-3 logger:

$client = OpenAI::client(
    getenv('OPENAI_API_KEY'),
    logger: new \Psr\Log\StreamLogger(fopen('php://stderr', 'w')),
);

Remove the logger in production to avoid leaking token counts or prompts to logs.

Wrapping up the setup

The openai-php client library setup boils down to three steps: require the package, build a client with a key, and call the resource methods. From there, streaming, Laravel binding, and gateway swapping are configuration changes, not code rewrites. Use typed responses, catch exceptions at the edge, and keep your API key out of source control.

Tagsphpopenai-phpclient-librarysetup

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All php & laravel llm integration posts →