Skip to content

rademakeronline/openrouter

Repository files navigation

OpenRouter Composer Wrapper

Composer-compatible PHP wrapper for the OpenRouter API, built on PSR-18.

Installation

composer require crademaker/openrouter-wrapper

Quick Start

<?php

declare(strict_types=1);

use Crademaker\OpenRouter\OpenRouterClient;
use Crademaker\OpenRouter\OpenRouterConfig;

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

$config = new OpenRouterConfig(
    apiKey: getenv('OPENROUTER_API_KEY') ?: '',
    appUrl: 'https://your-app.example',
    appName: 'My Composer App',
);

$client = new OpenRouterClient($config);

$response = $client->chatCompletions([
    'model' => 'openai/gpt-4o-mini',
    'messages' => [
        ['role' => 'system', 'content' => 'You are a helpful assistant.'],
        ['role' => 'user', 'content' => 'Say hello in one sentence.'],
    ],
]);

echo $response['choices'][0]['message']['content'] ?? 'No response';

Usage In Existing Projects

Standard installation via Packagist:

composer require crademaker/openrouter-wrapper

Minimal bootstrap in an existing project:

<?php

declare(strict_types=1);

use Crademaker\OpenRouter\OpenRouterClient;
use Crademaker\OpenRouter\OpenRouterConfig;

$client = new OpenRouterClient(
    new OpenRouterConfig(
        apiKey: $_ENV['OPENROUTER_API_KEY'] ?? '',
        appUrl: 'https://your-app.example',
        appName: 'Your Project Name',
    ),
);

Typical follow-up:

  • register the client as a service or singleton
  • inject OPENROUTER_API_KEY through .env, a secret store, or CI variables
  • use concrete model IDs instead of routing aliases if you need reproducible behavior

Language Policy

This repository follows a simple rule for public distribution:

  • public package surface is written in English
  • GitHub-facing documentation is written in English
  • Composer metadata is written in English
  • examples and release-facing documentation are written in English

This keeps the package aligned with common GitHub, Packagist, and Composer expectations.

Example READMEs

Common use cases are documented under examples/:

Typed DTO API

In addition to array payloads, the package provides semantic DTOs per endpoint group under Crademaker\OpenRouter\DTO\....

<?php

declare(strict_types=1);

use Crademaker\OpenRouter\DTO\Request\InferenceRequest;
use Crademaker\OpenRouter\DTO\Request\ListModelsQuery;
use Crademaker\OpenRouter\DTO\Request\ChatMessage;
use Crademaker\OpenRouter\Enum\ChatRole;
use Crademaker\OpenRouter\Enum\ModelCategory;
use Crademaker\OpenRouter\Enum\SupportedParameter;

$inference = $client->chatCompletionsDto(
    InferenceRequest::chat('openai/gpt-4o-mini', [
        ChatMessage::withRole(ChatRole::USER, 'Hello'),
    ]),
);

echo $inference->firstText() ?? 'No response';
echo $inference->firstChoice()?->message()?->role() ?? '';

$models = $client->listModelsDto(ListModelsQuery::create(
    category: ModelCategory::GENERAL,
    supportedParameters: SupportedParameter::TOOLS,
));
echo (string) $models->count();
echo $models->modelObjects()[0]->id();

Conventions:

  • array-based methods remain available for backward compatibility
  • ...Dto() methods return typed response objects
  • many array-based methods also accept request DTOs through union types

Examples of strict field objects:

  • Request: ChatMessage, InferenceRequest, EmbeddingsRequest, KeyRequest, GuardrailRequest
  • Response: InferenceChoice, ModelInfo, KeyInfo, GuardrailInfo, ProviderInfo, EmbeddingVector
  • Enums: ChatRole, ModelCategory, SupportedParameter (with enum|string fallback in query DTOs)

API Coverage

Coverage is based on the OpenRouter OpenAPI specification retrieved on March 5, 2026.

Inference

  • chatCompletions(array $payload) -> POST /chat/completions
  • completions(array $payload) -> POST /completions (Legacy-Alias)
  • createMessages(array $payload) -> POST /messages
  • createResponses(array $payload) -> POST /responses
  • createEmbeddings(array $payload) -> POST /embeddings
  • listEmbeddingsModels() -> GET /embeddings/models
  • getGeneration(string $id) -> GET /generation?id=...

Models And Providers

  • listModels(array $query = []) -> GET /models
  • listModelsCount() -> GET /models/count
  • listModelsUser() -> GET /models/user
  • listModelEndpoints(string $author, string $slug) -> GET /models/{author}/{slug}/endpoints
  • listProviders() -> GET /providers
  • listEndpointsZdr() -> GET /endpoints/zdr

Credits

  • getCredits() -> GET /credits
  • createCoinbaseCharge(array $payload) -> POST /credits/coinbase

API Keys And Auth

  • getCurrentKey() -> GET /key
  • listKeys(array $query = []) -> GET /keys
  • getKey(string $hash) -> GET /keys/{hash}
  • createKeys(array $payload) / createKey(array $payload) -> POST /keys
  • updateKeys(string $hash, array $payload) / updateKey(...) -> PATCH /keys/{hash}
  • deleteKeys(string $hash) / deleteKey(...) -> DELETE /keys/{hash}
  • exchangeAuthCodeForApiKey(array $payload) -> POST /auth/keys
  • createAuthorizationCode(array $payload) -> POST /auth/keys/code
  • getUserActivity(?string $date = null) -> GET /activity

Guardrails

  • listGuardrails(array $query = []) -> GET /guardrails
  • getGuardrail(string $id) -> GET /guardrails/{id}
  • createGuardrail(array $payload) -> POST /guardrails
  • updateGuardrail(string $id, array $payload) -> PATCH /guardrails/{id}
  • deleteGuardrail(string $id) -> DELETE /guardrails/{id}
  • listKeyAssignments(array $query = []) -> GET /guardrails/assignments/keys
  • listMemberAssignments(array $query = []) -> GET /guardrails/assignments/members
  • listGuardrailKeyAssignments(string $id, array $query = []) -> GET /guardrails/{id}/assignments/keys
  • listGuardrailMemberAssignments(string $id, array $query = []) -> GET /guardrails/{id}/assignments/members
  • bulkAssignKeysToGuardrail(string $id, array $payload) -> POST /guardrails/{id}/assignments/keys
  • bulkUnassignKeysFromGuardrail(string $id, array $payload) -> POST /guardrails/{id}/assignments/keys/remove
  • bulkAssignMembersToGuardrail(string $id, array $payload) -> POST /guardrails/{id}/assignments/members
  • bulkUnassignMembersFromGuardrail(string $id, array $payload) -> POST /guardrails/{id}/assignments/members/remove

Streaming / Raw Responses

Use requestRaw(...) for non-JSON responses such as SSE:

$response = $client->requestRaw('POST', '/responses', [
    'model' => 'openai/gpt-4o-mini',
    'input' => 'stream test',
    'stream' => true,
]);

$rawSse = (string) $response->getBody();

Error Handling

  • ApiException: non-2xx API response
  • TransportException: network or PSR-18 transport failure
  • InvalidResponseException: invalid JSON or JSON encoding failure

Development

composer validate
composer test
composer cs-check

Run live integration tests with a real API key (optional):

export OPENROUTER_API_KEY=...
composer test-integration

The integration test suite currently verifies:

  • live access to getCurrentKey()
  • live access to listModels()
  • live access to getCredits()
  • live access to listModelsCount()
  • live access to listModelsUser()
  • live access to listEmbeddingsModels()
  • a real embeddings request with nvidia/llama-nemotron-embed-vl-1b-v2:free
  • live access to listProviders()
  • live access to listEndpointsZdr()
  • live access to listModelEndpoints('stepfun', 'step-3.5-flash:free')
  • a real content query through chat/completions with stepfun/step-3.5-flash:free
  • a real content query through responses with stepfun/step-3.5-flash:free
  • a real content query through messages with stepfun/step-3.5-flash:free
  • a real streaming request through requestRaw() against /responses
  • a real image-input query through chat/completions with google/gemma-3-4b-it:free

Optional environment variables:

  • OPENROUTER_BASE_URL (default: https://openrouter.ai/api/v1)
  • OPENROUTER_APP_URL
  • OPENROUTER_APP_NAME
  • OPENROUTER_VISION_MODEL
  • OPENROUTER_TEST_IMAGE_URL

Lizenz

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages