Guias de SDK
PHP
Use o cliente openai-php/client com a api14: configure a base URI, faça chat, streaming, tool calling, saída estruturada e implemente retentativas com backoff.
Use o openai-php/client com a api14. Crie o cliente com a factory, defina a base URI para a api14 e use ids de modelo no formato provider/model.
Instalação
composer require openai-php/client guzzlehttp/guzzle
export API14_API_KEY="sk-api14-..."
Configuração
<?php
require __DIR__ . '/vendor/autoload.php';
$client = OpenAI::factory()
->withApiKey(getenv('API14_API_KEY'))
->withBaseUri(getenv('API14_BASE_URL') ?: 'https://api14.com/api/v1')
->withHttpClient(new \GuzzleHttp\Client(['timeout' => 120, 'connect_timeout' => 5]))
->make();
Mantenha a chave no ambiente (ou no .env do seu framework), nunca no código-fonte. O timeout do Guzzle é em segundos e cobre a requisição inteira; aumente-o para chamadas longas de raciocínio ou de streaming.
Chat
$result = $client->chat()->create([
'model' => 'openai/gpt-5-mini',
'messages' => [
['role' => 'user', 'content' => 'Explain vector databases in two sentences.'],
],
]);
echo $result->choices[0]->message->content;
Streaming
$stream = $client->chat()->createStreamed([
'model' => 'anthropic/claude-sonnet-4.5',
'messages' => [['role' => 'user', 'content' => 'Write a haiku about APIs.']],
]);
foreach ($stream as $response) {
echo $response->choices[0]->delta->content;
}
Veja Streaming.
Tool calling
$tools = [[
'type' => 'function',
'function' => [
'name' => 'get_weather',
'description' => 'Current weather for a city',
'parameters' => [
'type' => 'object',
'properties' => ['city' => ['type' => 'string']],
'required' => ['city'],
],
],
]];
$messages = [['role' => 'user', 'content' => "What's the weather in Istanbul?"]];
while (true) {
$response = $client->chat()->create(['model' => 'openai/gpt-5-mini', 'messages' => $messages, 'tools' => $tools]);
$message = $response->choices[0]->message;
if (empty($message->toolCalls)) {
echo $message->content;
break;
}
$messages[] = $message->toArray();
foreach ($message->toolCalls as $call) {
$args = json_decode($call->function->arguments, true);
$messages[] = [
'role' => 'tool',
'tool_call_id' => $call->id,
'content' => json_encode(getWeather($args['city'])), // sua função
];
}
}
Veja Tool calling.
Saída estruturada
$result = $client->chat()->create([
'model' => 'openai/gpt-5-mini',
'messages' => [['role' => 'user', 'content' => 'Extract: Ada Lovelace, born 1815 in London.']],
'response_format' => [
'type' => 'json_schema',
'json_schema' => [
'name' => 'person',
'strict' => true,
'schema' => [
'type' => 'object',
'properties' => [
'name' => ['type' => 'string'],
'born' => ['type' => 'integer'],
'city' => ['type' => 'string'],
],
'required' => ['name', 'born', 'city'],
'additionalProperties' => false,
],
],
],
]);
$person = json_decode($result->choices[0]->message->content, true, flags: JSON_THROW_ON_ERROR);
Veja Saídas estruturadas.
Entrada de imagem
$image = base64_encode(file_get_contents('photo.png'));
$result = $client->chat()->create([
'model' => 'google/gemini-2.5-flash',
'messages' => [[
'role' => 'user',
'content' => [
['type' => 'text', 'text' => 'What is in this picture?'],
['type' => 'image_url', 'image_url' => ['url' => "data:image/png;base64,{$image}"]],
],
]],
]);
Veja Visão e arquivos.
Embeddings
$result = $client->embeddings()->create([
'model' => 'openai/text-embedding-3-small',
'input' => ['The quick brown fox', 'Lorem ipsum'],
]);
echo count($result->embeddings[0]->embedding);
Fala
$audio = $client->audio()->speech([
'model' => 'openai/gpt-4o-mini-tts',
'input' => 'Hello from api14!',
'voice' => 'alloy',
]);
file_put_contents('speech.mp3', $audio);
Erros
Os erros do gateway usam o formato da OpenAI, então o cliente lança OpenAI\Exceptions\ErrorException com o status e o código legível por máquina:
use OpenAI\Exceptions\ErrorException;
try {
$client->chat()->create([
'model' => 'openai/gpt-5-mini',
'messages' => [['role' => 'user', 'content' => 'Hi']],
]);
} catch (ErrorException $e) {
match ($e->getStatusCode()) {
402 => error_log('Balance too low, add funds: ' . $e->getErrorCode()), // insufficient_balance
429 => error_log('Rate limited, retry in 60s: ' . $e->getErrorCode()), // rate_limited
default => throw $e,
};
}
O gateway envia Retry-After: 60 com rate_limited. Veja Limites de taxa e Erros.
Novas tentativas com backoff
O openai-php/client não repete chamadas por conta própria. Envolva as chamadas em um pequeno loop que repete rate_limited e 5xx e desiste de todo o resto:
use OpenAI\Exceptions\ErrorException;
use OpenAI\Exceptions\TransporterException;
function withRetry(callable $fn, int $attempts = 5): mixed
{
for ($i = 0; ; $i++) {
try {
return $fn();
} catch (ErrorException $e) {
$retryable = $e->getErrorCode() === 'rate_limited' || $e->getStatusCode() >= 500;
if (!$retryable || $i + 1 >= $attempts) throw $e;
} catch (TransporterException $e) { // erro de rede ou timeout
if ($i + 1 >= $attempts) throw $e;
}
usleep((min(60, 2 ** $i) * 1000 + random_int(0, 1000)) * 1000); // backoff + jitter
}
}
$result = withRetry(fn () => $client->chat()->create([
'model' => 'openai/gpt-5-mini',
'messages' => [['role' => 'user', 'content' => 'Hi']],
]));
daily_limit_reached e insufficient_balance não são repetidos, porque esperar alguns segundos não os resolve.
Todos os recursos
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api14.com/api/v1",
apiKey: process.env.API14_API_KEY,
});
const result = await client.chat.completions.create({
"model": "openai/gpt-5-mini",
"messages": [
{
"role": "user",
"content": "Explain vector databases in two sentences."
}
]
});
console.log(result.choices[0].message.content);