# OpenRouter API Documentation

## Overview

**OpenRouter** is a unified API gateway that provides access to hundreds of AI models from multiple providers (OpenAI, Anthropic, Google, Meta, Mistral, xAI, and more) through a single endpoint. It's **OpenAI SDK compatible**, making migration seamless.

**Official Documentation**: https://openrouter.ai/docs/  
**API Reference**: https://openrouter.ai/docs/api-reference/overview  
**Models**: https://openrouter.ai/models  
**Pricing**: https://openrouter.ai/docs/pricing

---

## Key Features

- **400+ Models**: Access to OpenAI, Anthropic, Google, Meta, Mistral, and more
- **OpenAI SDK Compatible**: Drop-in replacement for OpenAI API
- **Automatic Fallbacks**: If a model is down, automatically routes to alternatives
- **Cost Optimization**: Automatically selects most cost-effective models
- **Unified Interface**: Same API for all models
- **Credit Limits**: Set spending limits per API key
- **Zero Data Retention**: Optional ZDR mode for privacy

---

## Base URL

```
https://openrouter.ai/api/v1
```

**Note**: The endpoint structure is identical to OpenAI's API (`/chat/completions`, etc.)

---

## Authentication

OpenRouter uses **Bearer token** authentication, just like OpenAI.

### Getting an API Key

1. Visit https://openrouter.ai/keys
2. Create a new API key
3. Optionally set a credit limit
4. Keep it secret!

### Using the API Key

**HTTP Header**:
```bash
Authorization: Bearer YOUR_OPENROUTER_API_KEY
```

**Optional Headers** (for app attribution on OpenRouter leaderboard):
```bash
HTTP-Referer: YOUR_SITE_URL
X-Title: YOUR_APP_NAME
```

---

## Quick Start

### Using OpenAI SDK (Recommended)

OpenRouter is **100% compatible** with the OpenAI SDK. Just change the `base_url`:

#### Python

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key="YOUR_OPENROUTER_API_KEY",
)

completion = client.chat.completions.create(
    extra_headers={
        "HTTP-Referer": "YOUR_SITE_URL",  # Optional
        "X-Title": "YOUR_APP_NAME",       # Optional
    },
    model="openai/gpt-4o-mini",
    messages=[
        {
            "role": "user",
            "content": "What is SEO?"
        }
    ]
)

print(completion.choices[0].message.content)
```

#### JavaScript/TypeScript

```typescript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://openrouter.ai/api/v1',
  apiKey: process.env.OPENROUTER_API_KEY,
  defaultHeaders: {
    'HTTP-Referer': 'YOUR_SITE_URL',  // Optional
    'X-Title': 'YOUR_APP_NAME',       // Optional
  },
});

const completion = await client.chat.completions.create({
  model: 'openai/gpt-4o-mini',
  messages: [
    { role: 'user', content: 'What is SEO?' }
  ],
});

console.log(completion.choices[0].message.content);
```

### Using Direct HTTP Requests

#### curl

```bash
curl https://openrouter.ai/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "HTTP-Referer: YOUR_SITE_URL" \
  -H "X-Title: YOUR_APP_NAME" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "messages": [
      {"role": "user", "content": "What is SEO?"}
    ]
  }'
```

#### PHP

```php
use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'Authorization' => 'Bearer ' . env('OPENROUTER_API_KEY'),
    'HTTP-Referer' => 'YOUR_SITE_URL',
    'X-Title' => 'YOUR_APP_NAME',
])
->post('https://openrouter.ai/api/v1/chat/completions', [
    'model' => 'openai/gpt-4o-mini',
    'messages' => [
        ['role' => 'user', 'content' => 'What is SEO?']
    ],
]);

$result = $response->json();
echo $result['choices'][0]['message']['content'];
```

---

## Available Models

OpenRouter provides access to **400+ models**. Here are some popular ones:

### OpenAI Models

| Model ID | Description | Context | Cost (per 1M tokens) |
|----------|-------------|---------|---------------------|
| `openai/gpt-4o` | Latest GPT-4 Omni | 128K | Input: $2.50, Output: $10 |
| `openai/gpt-4o-mini` | Cost-effective GPT-4 | 128K | Input: $0.15, Output: $0.60 |
| `openai/gpt-5` | GPT-5 (if available) | Large | Check pricing |
| `openai/o3-mini` | Reasoning model | Large | Check pricing |

### Anthropic Models

| Model ID | Description | Context | Cost (per 1M tokens) |
|----------|-------------|---------|---------------------|
| `anthropic/claude-3.5-sonnet` | Latest Claude | 200K | Input: $3.00, Output: $15 |
| `anthropic/claude-3-haiku` | Fast, affordable | 200K | Input: $0.25, Output: $1.25 |

### Google Models

| Model ID | Description | Context | Cost (per 1M tokens) |
|----------|-------------|---------|---------------------|
| `google/gemini-2.0-flash-exp` | Latest Gemini | 1M | Often free |
| `google/gemini-pro-1.5` | Gemini Pro | 2M | Input: $1.25, Output: $5 |

### Meta Models

| Model ID | Description | Context | Cost (per 1M tokens) |
|----------|-------------|---------|---------------------|
| `meta-llama/llama-3.1-405b-instruct` | Largest Llama | 128K | Input: $2.70, Output: $2.70 |
| `meta-llama/llama-3.1-70b-instruct` | Mid-size Llama | 128K | Input: $0.35, Output: $0.40 |
| `meta-llama/llama-3.1-8b-instruct` | Small, fast Llama | 128K | Input: $0.06, Output: $0.06 |

### Other Popular Models

| Model ID | Description | Context | Cost (per 1M tokens) |
|----------|-------------|---------|---------------------|
| `mistralai/mistral-large` | Mistral flagship | 128K | Input: $2.00, Output: $6.00 |
| `x-ai/grok-2` | xAI's Grok | 128K | Check pricing |
| `deepseek/deepseek-chat` | DeepSeek | 64K | Very low cost |

**Full model list**: https://openrouter.ai/models

**Model Naming Convention**: `provider/model-name`

---

## Request Format

OpenRouter uses the **same request format as OpenAI Chat Completions API**.

### Basic Request

```json
{
  "model": "openai/gpt-4o-mini",
  "messages": [
    {"role": "system", "content": "You are an SEO expert."},
    {"role": "user", "content": "Extract keywords from this text..."}
  ]
}
```

### Common Parameters

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `model` | string | Model ID (e.g., `openai/gpt-4o-mini`) | Required |
| `messages` | array | Array of message objects | Required |
| `temperature` | number | Sampling temperature (0-2) | 1.0 |
| `max_tokens` | integer | Maximum tokens to generate | Model default |
| `top_p` | number | Nucleus sampling (0-1) | 1.0 |
| `stream` | boolean | Enable streaming | false |
| `response_format` | object | Force JSON output: `{"type": "json_object"}` | null |
| `stop` | string/array | Stop sequences | null |

### OpenRouter-Specific Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `provider` | object | Provider preferences (see Provider Routing) |
| `transforms` | array | Message transforms |
| `route` | string | Routing strategy: `fallback` or `cost` |

---

## Response Format

Identical to OpenAI's response format:

```json
{
  "id": "gen-abc123",
  "model": "openai/gpt-4o-mini",
  "object": "chat.completion",
  "created": 1677858242,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "SEO stands for Search Engine Optimization..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 20,
    "completion_tokens": 50,
    "total_tokens": 70
  }
}
```

---

## Code Examples for SEO Tool

### PHP (Laravel) Service

```php
<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class OpenRouterService
{
    private $apiKey;
    private $baseUrl = 'https://openrouter.ai/api/v1';
    
    public function __construct()
    {
        $this->apiKey = config('services.openrouter.api_key');
    }
    
    public function chatCompletion(array $messages, string $model = 'openai/gpt-4o-mini', array $options = [])
    {
        $payload = array_merge([
            'model' => $model,
            'messages' => $messages,
        ], $options);
        
        $response = Http::withHeaders([
            'Authorization' => 'Bearer ' . $this->apiKey,
            'Content-Type' => 'application/json',
            'HTTP-Referer' => config('app.url'),
            'X-Title' => config('app.name'),
        ])
        ->timeout(60)
        ->post($this->baseUrl . '/chat/completions', $payload);
        
        if ($response->successful()) {
            return $response->json();
        }
        
        throw new \Exception('OpenRouter API error: ' . $response->body());
    }
    
    public function extractKeywords(string $content, string $pageType = 'product')
    {
        $messages = [
            [
                'role' => 'system',
                'content' => 'You are an SEO expert. Extract 15-20 relevant keyword candidates from the provided content. Return them as a JSON array with fields: keyword, relevance_score (0-100), and search_intent (informational/commercial/transactional).'
            ],
            [
                'role' => 'user',
                'content' => "Page type: {$pageType}\n\nContent:\n{$content}"
            ]
        ];
        
        $response = $this->chatCompletion($messages, 'openai/gpt-4o-mini', [
            'temperature' => 0.3,
            'response_format' => ['type' => 'json_object'],
            'max_tokens' => 500,
        ]);
        
        return json_decode($response['choices'][0]['message']['content'], true);
    }
    
    public function analyzeCompetitors(array $competitorContents, string $targetKeyword)
    {
        $competitorText = implode("\n\n---\n\n", $competitorContents);
        
        $messages = [
            [
                'role' => 'system',
                'content' => 'You are an SEO content strategist. Analyze competitor content and identify common topics, keywords, and content gaps.'
            ],
            [
                'role' => 'user',
                'content' => "Target keyword: {$targetKeyword}\n\nCompetitor content:\n{$competitorText}\n\nIdentify: 1) Common topics, 2) Semantic keywords, 3) Content depth. Return JSON."
            ]
        ];
        
        $response = $this->chatCompletion($messages, 'openai/gpt-4o-mini', [
            'temperature' => 0.3,
            'response_format' => ['type' => 'json_object'],
        ]);
        
        return json_decode($response['choices'][0]['message']['content'], true);
    }
}
```

### Using Alternative Models

```php
// Use cheaper model for simple extraction
$keywords = $this->chatCompletion($messages, 'meta-llama/llama-3.1-8b-instruct');

// Use Claude for complex analysis
$analysis = $this->chatCompletion($messages, 'anthropic/claude-3-haiku');

// Use free Gemini for high volume
$keywords = $this->chatCompletion($messages, 'google/gemini-2.0-flash-exp');
```

### Error Handling

```php
try {
    $response = $this->chatCompletion($messages);
} catch (\Exception $e) {
    $errorBody = $e->getMessage();
    
    // Check for rate limit
    if (str_contains($errorBody, 'rate_limit') || str_contains($errorBody, '429')) {
        Log::warning('OpenRouter rate limit hit, retrying...');
        sleep(2);
        return $this->chatCompletion($messages);
    }
    
    // Check for model unavailable
    if (str_contains($errorBody, 'model') && str_contains($errorBody, 'unavailable')) {
        Log::warning('Model unavailable, falling back to alternative');
        // OpenRouter automatically handles this, but you can also manually fallback
        return $this->chatCompletion($messages, 'meta-llama/llama-3.1-70b-instruct');
    }
    
    // Server error
    if (str_contains($errorBody, '500') || str_contains($errorBody, '503')) {
        Log::error('OpenRouter server error, retrying with backoff');
        sleep(5);
        return $this->chatCompletion($messages);
    }
    
    // Log and fail
    Log::error('OpenRouter API error', ['error' => $errorBody]);
    throw $e;
}
```

### Tracking API Usage

```php
public function chatCompletion(array $messages, string $model = 'openai/gpt-4o-mini', array $options = [])
{
    $response = Http::withHeaders([...])
        ->post($this->baseUrl . '/chat/completions', $payload);
    
    $result = $response->json();
    
    // Log usage
    \App\Models\ApiUsageLog::create([
        'service' => 'openrouter',
        'model' => $result['model'] ?? $model,
        'prompt_tokens' => $result['usage']['prompt_tokens'] ?? 0,
        'completion_tokens' => $result['usage']['completion_tokens'] ?? 0,
        'total_tokens' => $result['usage']['total_tokens'] ?? 0,
        'cost' => $this->calculateCost($result),
    ]);
    
    return $result;
}

private function calculateCost($response)
{
    // OpenRouter provides cost in response
    // Check $response['usage'] for cost information
    // Or calculate based on model pricing
    
    $model = $response['model'];
    $inputTokens = $response['usage']['prompt_tokens'];
    $outputTokens = $response['usage']['completion_tokens'];
    
    // Approximate costs (check openrouter.ai/models for current pricing)
    $prices = [
        'openai/gpt-4o-mini' => ['input' => 0.15, 'output' => 0.60],
        'anthropic/claude-3-haiku' => ['input' => 0.25, 'output' => 1.25],
        'meta-llama/llama-3.1-8b-instruct' => ['input' => 0.06, 'output' => 0.06],
    ];
    
    $price = $prices[$model] ?? $prices['openai/gpt-4o-mini'];
    
    $inputCost = ($inputTokens / 1000000) * $price['input'];
    $outputCost = ($outputTokens / 1000000) * $price['output'];
    
    return $inputCost + $outputCost;
}
```

---

## Advanced Features

### 1. Automatic Fallbacks

OpenRouter automatically routes to alternative models if the primary model is unavailable:

```php
$response = $this->chatCompletion($messages, 'openai/gpt-4o-mini', [
    'route' => 'fallback', // Enable automatic fallbacks
]);
```

### 2. Cost Optimization

Let OpenRouter automatically select the cheapest model that meets your requirements:

```php
$response = $this->chatCompletion($messages, 'openai/gpt-4o-mini', [
    'route' => 'cost', // Optimize for cost
]);
```

### 3. Provider Preferences

Specify provider preferences:

```php
$response = $this->chatCompletion($messages, 'openai/gpt-4o-mini', [
    'provider' => [
        'order' => ['OpenAI', 'Together'],
        'require_parameters' => true,
    ],
]);
```

### 4. Structured Outputs (JSON Mode)

```php
$response = $this->chatCompletion($messages, 'openai/gpt-4o-mini', [
    'response_format' => ['type' => 'json_object'],
]);
```

**Note**: Only supported by OpenAI models, Nitro models, and some others. Check model page for support.

### 5. Streaming

```php
// Not shown in detail, but OpenRouter supports streaming
// See: https://openrouter.ai/docs/api-reference/streaming
```

---

## Rate Limits

Rate limits vary by:
- Your account tier
- The specific model being used
- Provider limits

**Best Practices**:
- Add delays between requests (50-100ms)
- Implement exponential backoff on errors
- Monitor rate limit headers in responses

---

## Pricing

### How Pricing Works

- **Pay-as-you-go**: You're charged based on actual token usage
- **Per-model pricing**: Each model has different costs
- **No markup on most models**: OpenRouter passes through provider pricing
- **Credit system**: Add credits to your account

### Cost Comparison

For 100-page SEO analysis (assuming 500 input tokens, 300 output tokens per page):

| Model | Input Cost | Output Cost | Total (100 pages) |
|-------|-----------|-------------|-------------------|
| `openai/gpt-4o-mini` | $0.0075 | $0.018 | **$0.0255** |
| `anthropic/claude-3-haiku` | $0.0125 | $0.0375 | **$0.05** |
| `meta-llama/llama-3.1-8b-instruct` | $0.003 | $0.0018 | **$0.0048** |
| `google/gemini-2.0-flash-exp` | Free | Free | **$0** |

**Recommendation for SEO tool**: Start with `openai/gpt-4o-mini` for quality, or use `meta-llama/llama-3.1-8b-instruct` for cost savings.

---

## Environment Configuration (.env)

```env
# OpenRouter Configuration
OPENROUTER_API_KEY=sk-or-v1-...
OPENROUTER_MODEL=openai/gpt-4o-mini
OPENROUTER_TEMPERATURE=0.3
OPENROUTER_MAX_TOKENS=500

# Alternative models for different tasks
OPENROUTER_CHEAP_MODEL=meta-llama/llama-3.1-8b-instruct
OPENROUTER_ADVANCED_MODEL=anthropic/claude-3.5-sonnet
```

---

## Best Practices for SEO Tool

### 1. Model Selection Strategy

```php
class AIModelSelector
{
    public function selectModel(string $task)
    {
        return match($task) {
            'keyword_extraction' => 'openai/gpt-4o-mini',
            'competitor_analysis' => 'anthropic/claude-3-haiku',
            'simple_classification' => 'meta-llama/llama-3.1-8b-instruct',
            'complex_reasoning' => 'openai/gpt-4o',
            default => 'openai/gpt-4o-mini',
        };
    }
}
```

### 2. Implement Caching

```php
public function extractKeywordsWithCache(string $content, string $pageType)
{
    $cacheKey = 'ai_keywords_' . md5($content);
    
    return Cache::remember($cacheKey, now()->addDays(7), function () use ($content, $pageType) {
        return $this->extractKeywords($content, $pageType);
    });
}
```

### 3. Batch Processing

```php
public function processBatch(array $pages)
{
    foreach ($pages as $page) {
        try {
            $keywords = $this->extractKeywords($page->content, $page->type);
            $page->update(['keywords' => $keywords, 'status' => 'analyzed']);
            
            // Rate limiting
            usleep(50000); // 50ms delay
            
        } catch (\Exception $e) {
            Log::error('AI processing failed', ['page_id' => $page->id]);
            $page->update(['status' => 'failed']);
        }
    }
}
```

### 4. Cost Monitoring

```php
// Get total API costs
$totalCost = ApiUsageLog::where('service', 'openrouter')
    ->whereDate('created_at', today())
    ->sum('cost');

// Alert if over budget
if ($totalCost > config('services.openrouter.daily_budget')) {
    // Send alert, pause processing, etc.
}
```

---

## Comparison: OpenRouter vs OpenAI Direct

| Feature | OpenRouter | OpenAI Direct |
|---------|-----------|---------------|
| **Models** | 400+ from multiple providers | OpenAI models only |
| **Pricing** | Competitive, often same as direct | Standard OpenAI pricing |
| **Fallbacks** | Automatic | Manual implementation needed |
| **API Format** | OpenAI-compatible | OpenAI native |
| **Setup** | Change base URL only | N/A |
| **Cost Optimization** | Built-in routing | Manual |
| **Rate Limits** | Per-model varies | OpenAI limits |

---

## Troubleshooting

### Issue: Model Not Available

**Solution**: OpenRouter automatically handles fallbacks, or manually specify alternative:

```php
try {
    $response = $this->chatCompletion($messages, 'openai/gpt-4o-mini');
} catch (\Exception $e) {
    // Fallback to alternative model
    $response = $this->chatCompletion($messages, 'meta-llama/llama-3.1-70b-instruct');
}
```

### Issue: Rate Limit Exceeded

**Solution**: Implement exponential backoff

```php
$maxRetries = 3;
$delay = 1;

for ($i = 0; $i < $maxRetries; $i++) {
    try {
        return $this->chatCompletion($messages);
    } catch (\Exception $e) {
        if ($i < $maxRetries - 1) {
            sleep($delay);
            $delay *= 2; // Exponential backoff
        } else {
            throw $e;
        }
    }
}
```

### Issue: Unexpected Response Format

**Solution**: Always validate response structure

```php
$response = $this->chatCompletion($messages);

if (!isset($response['choices'][0]['message']['content'])) {
    Log::error('Unexpected OpenRouter response', ['response' => $response]);
    throw new \Exception('Invalid API response');
}

return $response['choices'][0]['message']['content'];
```

---

## Additional Resources

- **Official Documentation**: https://openrouter.ai/docs/
- **API Reference**: https://openrouter.ai/docs/api-reference/overview
- **Models List**: https://openrouter.ai/models
- **Pricing**: https://openrouter.ai/docs/pricing
- **Quickstart**: https://openrouter.ai/docs/quickstart
- **Request Builder**: https://openrouter.ai/playground
- **Discord Community**: https://discord.gg/openrouter

---

## Summary for SEO Tool Implementation

### Why Use OpenRouter?

1. **Flexibility**: Access 400+ models through one API
2. **Cost Savings**: Use cheaper models like Llama or free Gemini for simple tasks
3. **Reliability**: Automatic fallbacks if a model is down
4. **OpenAI Compatible**: Drop-in replacement, minimal code changes
5. **No Vendor Lock-in**: Easy to switch between models

### Recommended Setup

```php
// config/services.php
'openrouter' => [
    'api_key' => env('OPENROUTER_API_KEY'),
    'default_model' => env('OPENROUTER_MODEL', 'openai/gpt-4o-mini'),
    'cheap_model' => 'meta-llama/llama-3.1-8b-instruct',
    'advanced_model' => 'anthropic/claude-3-haiku',
    'daily_budget' => 10.00, // $10/day limit
],
```

### Model Selection for SEO Tool

- **Keyword Extraction**: `openai/gpt-4o-mini` (best quality/cost balance)
- **Competitor Analysis**: `anthropic/claude-3-haiku` (good reasoning)
- **Simple Classification**: `meta-llama/llama-3.1-8b-instruct` (cheapest)
- **High Volume**: `google/gemini-2.0-flash-exp` (free!)

### Estimated Costs

For 100-page analysis:
- With `openai/gpt-4o-mini`: ~$0.03
- With `meta-llama/llama-3.1-8b-instruct`: ~$0.005
- With `google/gemini-2.0-flash-exp`: **$0** (free)

**OpenRouter gives you the flexibility to optimize costs while maintaining quality.**

