PHP code example of michaelfrank-dev / openrouter-php
1. Go to this page and download the library: Download michaelfrank-dev/openrouter-php library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
michaelfrank-dev / openrouter-php example snippets
use MichaelFrank\OpenRouter\Client\OpenRouterFactory;
// Automatically discovers PSR-18 and PSR-17 implementations
$client = OpenRouterFactory::create(
apiKey: $_ENV['OPENROUTER_API_KEY'],
siteUrl: 'https://myapp.com',
siteName: 'My Application'
);
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\CompletionOptions;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
use MichaelFrank\OpenRouter\Requests\ProviderPreferences;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\ProviderSort;
$request = new CompletionRequest(
model: '~openai/gpt-mini-latest',
messages: [new UserMessage('Write a short poem about Rio de Janeiro.')],
options: (new CompletionOptions())
->withProviderPreferences(
new ProviderPreferences(sort: new ProviderSort(ProviderSort::PRICE))
),
);
$response = $client->completions($request);
echo $response->getFirstChoice()->message->content;
use MichaelFrank\OpenRouter\Requests\ProviderPreferences;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\PercentileCutoffs;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\ProviderSort;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\ProviderSortConfig;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\ProviderSortPartition;
$provider = new ProviderPreferences(
order: ['anthropic', 'openai'],
sort: new ProviderSortConfig(
by: new ProviderSort(ProviderSort::THROUGHPUT),
partition: new ProviderSortPartition(ProviderSortPartition::MODEL),
),
preferredMinThroughput: new PercentileCutoffs(p50: 100.0),
preferredMaxLatency: new PercentileCutoffs(p50: 0.5, p99: 2.0),
maxPrice: ['prompt' => '0.55', 'completion' => '5.65'],
);
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
$request = new CompletionRequest(
model: ['~openai/gpt-mini-latest', '~anthropic/claude-haiku-latest'],
messages: [new UserMessage('How is it going?')],
);
$response = $client->completions($request);
use MichaelFrank\OpenRouter\Requests\ModelListQuery;
use MichaelFrank\OpenRouter\Requests\ModelListSort;
$models = $client->models(
new ModelListQuery(
sort: new ModelListSort(ModelListSort::THROUGHPUT_HIGH_TO_LOW),
outputModalities: 'text',
),
);
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\CompletionOptions;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
use MichaelFrank\OpenRouter\Requests\Tools\OpenRouterWebSearchTool;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\SearchContextSize;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\WebSearchEngine;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\UserLocation;
$request = new CompletionRequest(
model: '~anthropic/claude-haiku-latest',
messages: [new UserMessage('Historical landmarks and tourist sites to visit in Recife')],
options: new CompletionOptions(
tools: [
new OpenRouterWebSearchTool(
engine: new WebSearchEngine(WebSearchEngine::EXA), // exa, auto, native, firecrawl, parallel, perplexity
maxResults: 5, // results per search call
maxTotalResults: 15, // max cumulative results across searches
searchContextSize: new SearchContextSize(SearchContextSize::MEDIUM), // low, medium, high
maxCharacters: 2000, // exact max characters of content per result
allowedDomains: ['wikipedia.org', 'reddit.com'], // restrict search to these domains
excludedDomains: ['pinterest.com'], // exclude these domains
userLocation: new UserLocation( // geographic bias for search results (does not inject context into reasoning)
city: 'Belo Horizonte',
region: 'Minas Gerais',
country: 'Brazil',
timezone: 'America/Sao_Paulo'
),
maxUses: 3, // cap the number of searches model can perform
xSearch: true // enable X/Twitter search for SpaceXAI/Grok (or pass XSearchFilter)
)
]
)
);
$response = $client->completions($request);
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\CompletionOptions;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
use MichaelFrank\OpenRouter\Requests\Tools\OpenRouterWebFetchTool;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\WebFetchEngine;
$request = new CompletionRequest(
model: '~openai/gpt-mini-latest',
messages: [new UserMessage('Analyze the content on this webpage.')],
options: new CompletionOptions(
tools: [
new OpenRouterWebFetchTool(
engine: new WebFetchEngine(WebFetchEngine::AUTO),
url: 'https://example.com',
maxContentTokens: 1000,
allowedDomains: ['example.com'],
blockedDomains: ['irrelevant-site.com'], // filter out domains not relevant to the search
maxUses: 2
)
]
)
);
$response = $client->completions($request);
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\CompletionOptions;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
use MichaelFrank\OpenRouter\Requests\Tools\OpenRouterImageGenerationTool;
use MichaelFrank\OpenRouter\Enums\ImageQuality;
use MichaelFrank\OpenRouter\Enums\ImageBackground;
use MichaelFrank\OpenRouter\Enums\ImageOutputFormat;
$request = new CompletionRequest(
model: 'openai/gpt-5.2',
messages: [new UserMessage('Create an image of a futuristic city at sunset')],
options: new CompletionOptions(
tools: [
new OpenRouterImageGenerationTool(
model: 'openai/gpt-image-2', // which image generation model to use
quality: ImageQuality::High, // Auto, Low, Medium, High
aspectRatio: '16:9',
size: '1024x1024',
background: ImageBackground::Transparent, // Auto, Transparent, Opaque
outputFormat: ImageOutputFormat::Png, // Png, Jpeg, Webp, Svg
outputCompression: 85,
moderation: 'auto'
)
]
)
);
$response = $client->completions($request);
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\CompletionOptions;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\SearchContextSize;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\WebSearchOptions;
$request = new CompletionRequest(
model: '~deepseek/deepseek-v4-flash-latest',
messages: [new UserMessage('What are the latest developments in quantum computing?')],
options: (new CompletionOptions())
->withWebSearchOptions(
new WebSearchOptions(new SearchContextSize(SearchContextSize::LOW))
)
);
$response = $client->completions($request);
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\CompletionOptions;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
use MichaelFrank\OpenRouter\Requests\ProviderRouting\XSearchFilter;
use MichaelFrank\OpenRouter\Requests\Tools\OpenRouterWebSearchTool;
// With search filters:
$request = new CompletionRequest(
model: '~x-ai/grok-latest',
messages: [new UserMessage('What did OpenRouter announce this year?')],
options: new CompletionOptions(
tools: [
new OpenRouterWebSearchTool(
xSearch: new XSearchFilter(
allowedXHandles: ['OpenRouterAI'],
fromDate: '2026-01-01',
toDate: '2026-06-01',
enableImageUnderstanding: true,
enableVideoUnderstanding: false
)
)
]
)
);
$response = $client->completions($request);
// Enable X Search with no filters:
$options = new CompletionOptions(
tools: [
new OpenRouterWebSearchTool(
xSearch: true // or: XSearchFilter::enabled()
)
]
);
use MichaelFrank\OpenRouter\Requests\Tools\SpaceXXSearchTool;
// Direct SpaceXAI { "type": "x_search" } tool:
$options = new CompletionOptions(
tools: [
new SpaceXXSearchTool()
]
);
use GuzzleHttp\Client as GuzzleClient;
use MichaelFrank\OpenRouter\Client\OpenRouterFactory;
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
// Make sure to configure Guzzle with stream => true to disable response buffering
$httpClient = new GuzzleClient(['stream' => true]);
$client = OpenRouterFactory::create(
apiKey: $_ENV['OPENROUTER_API_KEY'],
httpClient: $httpClient
);
$request = new CompletionRequest(
model: 'meta-llama/llama-3-8b-instruct',
messages: [new UserMessage('Write a poem about the Saci-Pererê, a mischievous Brazilian folklore character.')]
);
$chunks = $client->streamCompletions($request);
foreach ($chunks as $chunk) {
echo $chunk->choices[0]->delta->content ?? '';
}
use MichaelFrank\OpenRouter\Requests\EmbeddingRequest;
$request = new EmbeddingRequest(
model: 'text-embedding-3-small',
input: 'Feijoada is one of the most traditional dishes in Brazilian cuisine.'
);
$response = $client->embeddings($request);
foreach ($response->data as $item) {
// $item->embedding is an array of floats
print_r($item->embedding);
}
use MichaelFrank\OpenRouter\Requests\RerankRequest;
$request = new RerankRequest(
model: 'cohere/rerank-english-v3.0',
query: 'What is the capital of Brazil?',
documents: [
'Brasilia is the capital of Brazil.',
'Rio de Janeiro was the capital of Brazil until 1960 and remains a major cultural and touristic center.',
'Sao Paulo is the largest city in Brazil by population and a major economic hub.'
],
topN: 2
);
$response = $client->rerank($request);
foreach ($response->results as $result) {
echo "Index: {$result->index}, Relevance Score: {$result->relevanceScore}\n";
}
use MichaelFrank\OpenRouter\Requests\AudioSpeechRequest;
$request = new AudioSpeechRequest(
model: 'openai/tts-1',
input: 'The Iguaçu Falls roar with the power of millions of liters of water, creating one of the most breathtaking and unforgettable landscapes on the planet.',
voice: 'alloy',
responseFormat: 'mp3'
);
$response = $client->speech($request);
// Save the audio stream contents directly to a file
$response->saveToFile(__DIR__ . '/output.mp3');
use MichaelFrank\OpenRouter\Requests\ImageGenerationRequest;
use MichaelFrank\OpenRouter\Requests\ImageGenerationProviderPreferences;
use MichaelFrank\OpenRouter\Requests\ImageResolution;
use MichaelFrank\OpenRouter\Enums\ImageOutputFormat;
use MichaelFrank\OpenRouter\Enums\ImageBackground;
$request = new ImageGenerationRequest(
model: 'krea/krea-2-medium-turbo',
prompt: 'A sleek retro-futuristic hovercar parked on a neon-lit street in Tokyo, cyberpunk style, hyper-detailed',
aspectRatio: '16:9',
outputFormat: ImageOutputFormat::Png,
resolution: new ImageResolution('512x512'), // Supports constants (e.g. ImageResolution::TWO_K) or custom strings (e.g. '1K', '512x512')
background: ImageBackground::Auto,
provider: new ImageGenerationProviderPreferences(
allowFallbacks: false,
only: ['google-ai-studio']
)
);
// Standard image generation
$response = $client->images($request);
foreach ($response->data as $item) {
// $item->b64Json is base64 encoded image bytes string
$imageBytes = base64_decode($item->b64Json);
file_put_contents(__DIR__ . '/hovercar.png', $imageBytes);
}
// Streaming image generation (SSE events)
$streamRequest = $request->withStream(true);
$chunks = $client->streamImages($streamRequest);
foreach ($chunks as $chunk) {
// Each chunk contains one of: ImageGenPartialImageEvent, ImageGenTextChunkEvent, ImageGenCompletedEvent
$event = $chunk->data;
if ($event->getType() === 'image_generation.completed') {
echo "Image generation complete!\n";
}
}
use MichaelFrank\OpenRouter\Requests\CompletionOptions;
use MichaelFrank\OpenRouter\Requests\CompletionRequest;
use MichaelFrank\OpenRouter\Requests\Messages\AssistantMessage;
use MichaelFrank\OpenRouter\Requests\Messages\AssistantMessageToolCall;
use MichaelFrank\OpenRouter\Requests\Messages\ToolMessage;
use MichaelFrank\OpenRouter\Requests\Messages\UserMessage;
use MichaelFrank\OpenRouter\Requests\Tools\ToolDefinition;
// Define the tool schema
$weatherTool = new ToolDefinition(
name: 'get_current_weather',
description: 'Get the current weather for a specified location',
parameters: [
'type' => 'object',
'properties' => [
'location' => [
'type' => 'string',
'description' => 'The city to search for'
],
'unit' => [
'type' => 'string',
'enum' => ['celsius', 'fahrenheit']
]
],
' [
'name' => $toolCall->function->name,
'arguments' => $toolCall->function->arguments
]
);
$followUpRequest = new CompletionRequest(
model: '~openai/gpt-mini-latest',
messages: [
new UserMessage('What is the weather like in Florianópolis?'),
new AssistantMessage(toolCalls: [$assistantToolCall]),
new ToolMessage(content: $weatherResult, toolCallId: $toolCall->id)
]
);
$finalResponse = $client->completions($followUpRequest);
echo $finalResponse->getFirstChoice()->message->content;
}
}
}