AI Router

de Publieke Partner — AI Proxy Router Documentation

A Cloudflare Worker-based AI prompt router with multi-provider support, priority-based fallback, and usage analytics.

Features

  • Multi-Provider Support — Route prompts to 1min.ai, Straico, OpenAI, and more
  • Priority-Based Fallback — Automatic failover when providers are unavailable
  • Credit-Based Routing — Select models based on available credits
  • Usage Analytics — Track calls, tokens, latency, and errors
  • Admin UI — Visual configuration interface
  • Google OAuth — Secure admin access restricted to @depubliekepartner.nl

Architecture

┌─────────────┐     ┌──────────────────┐     ┌─────────────┐
│   Client    │────▶│  Worker (Hono)   │────▶│  AI Provider│
└─────────────┘     └────────┬─────────┘     └─────────────┘
                             │
                    ┌────────▼─────────┐
                    │     D1 (SQLite)  │
                    │  - providers     │
                    │  - models        │
                    │  - api_keys      │
                    │  - routes        │
                    │  - usage_logs    │
                    └──────────────────┘

Quick Start

Get started with the AI Router API in minutes.

Base URL

https://ai-router.dpp-ai.workers.dev

Basic Request

curl -X POST https://ai-router.dpp-ai.workers.dev/v1/prompt \
  -H "Authorization: Bearer $PROXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Explain quantum computing in simple terms"
  }'

Response

{
  "response": "Quantum computing uses quantum mechanics...",
  "provider": "openai",
  "model": "gpt-4o",
  "usage": {
    "prompt_tokens": 8,
    "completion_tokens": 150
  }
}

Authentication

The prompt API requires an API key. Admin endpoints require Google OAuth authentication.

Prompt API Key

Include an API key on every /v1/prompt request.

Authorization: Bearer <key>
x-api-key: <key>
Access Restriction

Admin access is restricted to @depubliekepartner.nl Google accounts only.

Admin Authentication Flow

  1. Navigate to /auth/login
  2. Sign in with your @depubliekepartner.nl Google account
  3. You'll be redirected back with a session cookie
  4. All /admin/* endpoints will now work

Logout

GET /auth/logout

Prompt API

The main endpoint for sending prompts to AI providers. Include Authorization: Bearer <key> or x-api-key on every request.

POST /v1/prompt
Send a prompt to the AI router

Request Body

FieldTypeRequiredDescription
promptstringYesThe prompt text to send
creditsnumberNoAvailable credits (filters routes by min_credits)
providerstringNoForce specific provider (e.g., "openai")
modelstringNoForce specific model (e.g., "gpt-4o")

Response

FieldTypeDescription
responsestringThe AI-generated response
providerstringProvider that handled the request
modelstringModel that generated the response
usageobjectToken usage statistics

Example with Options

curl -X POST https://ai-router.dpp-ai.workers.dev/v1/prompt \
  -H "Authorization: Bearer $PROXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Write a haiku about coding",
    "credits": 100,
    "provider": "openai"
  }'

Providers

Manage AI provider configurations.

GET /admin/providers
List all providers
POST /admin/providers
Create or update a provider
DELETE /admin/providers/:id
Delete a provider

Provider Object

FieldTypeDescription
idstringUnique identifier
namestringDisplay name
base_urlstringAPI endpoint URL
auth_typestringAuthentication type (default: "api_key")
prioritynumberLower = higher priority
activenumber1 = enabled, 0 = disabled

Pre-configured Providers

IDNameBase URL
1min1min.aihttps://api.1min.ai/api/features
straicoStraicohttps://api.straico.com/v0/prompt/completion
openaiOpenAIhttps://api.openai.com/v1/chat/completions

Models

Manage AI model configurations per provider.

GET /admin/models
List all models
POST /admin/models
Create or update a model
DELETE /admin/models/:id
Delete a model

Model Object

FieldTypeDescription
idstringUnique identifier
provider_idstringReference to provider
model_idstringProvider's model identifier
namestringDisplay name
cost_per_1knumberCost per 1000 tokens
activenumber1 = enabled, 0 = disabled

Routes

Configure routing rules for prompt distribution.

GET /admin/routes
List all routes
POST /admin/routes
Create or update a route
DELETE /admin/routes/:id
Delete a route

Route Object

FieldTypeDescription
idstringUnique identifier
namestringDisplay name
provider_idstringTarget provider
model_idstringTarget model
prioritynumberLower = tried first
min_creditsnumberMinimum credits required
activenumber1 = enabled, 0 = disabled
How Routing Works

Routes are sorted by priority (ascending). The router tries each route in order until one succeeds. If a provider fails, it automatically falls back to the next route.

API Keys

Manage API keys for providers. Keys are stored encrypted and never exposed in responses.

GET /admin/keys
List all API keys (without values)
POST /admin/keys
Create or update an API key
DELETE /admin/keys/:id
Delete an API key

Creating an API Key

curl -X POST https://ai-router.dpp-ai.workers.dev/admin/keys \
  -H "Content-Type: application/json" \
  -H "Cookie: ai_router_session=..." \
  -d '{
    "provider_id": "openai",
    "key_value": "sk-...",
    "label": "Production Key"
  }'

Statistics

View usage analytics and performance metrics.

GET /admin/stats
Get usage statistics

Query Parameters

ParameterDefaultDescription
range7dTime range (e.g., "7d", "30d")

Response

[
  {
    "provider_id": "openai",
    "total_calls": 1500,
    "success_count": 1480,
    "error_count": 20,
    "avg_latency": 245.5,
    "total_tokens": 150000
  }
]

Adding Custom Providers

Extend the router with additional AI providers.

1. Add Provider Handler

Edit src/providers.ts:

export async function callCustomProvider(o: CallOpts): Promise<AIResp> {
  const res = await fetch(o.baseUrl, {
    method: 'POST',
    headers: {
      'Authorization': \`Bearer \${o.apiKey}\`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: o.model,
      prompt: o.prompt,
    }),
  });

  const data = await res.json();
  return {
    response: data.text,
    provider: 'custom',
    model: o.model,
    usage: data.usage,
  };
}

// Register in getProviderFn
export function getProviderFn(id: string) {
  const map = {
    '1min': call1min,
    'straico': callStraico,
    'openai': callOpenAI,
    'custom': callCustomProvider, // Add here
  };
  return map[id] || null;
}

2. Add Provider via Admin

curl -X POST https://ai-router.dpp-ai.workers.dev/admin/providers \
  -H "Content-Type: application/json" \
  -d '{
    "id": "custom",
    "name": "Custom Provider",
    "base_url": "https://api.custom.ai/v1/complete",
    "priority": 4
  }'

Fallback Routing

Configure automatic failover between providers.

Strategy

  1. Routes sorted by priority (ascending)
  2. First matching route is attempted
  3. On failure, next route is tried
  4. All failures logged to usage_logs

Example Configuration

// Primary: OpenAI GPT-4
{ "name": "Primary", "provider_id": "openai", "model_id": "gpt-4o", "priority": 1 }

// Fallback 1: Straico Claude
{ "name": "Fallback 1", "provider_id": "straico", "model_id": "claude-3-5-sonnet", "priority": 2 }

// Fallback 2: 1min.ai
{ "name": "Fallback 2", "provider_id": "1min", "model_id": "gpt-4o", "priority": 3 }

Error Handling

Understanding API error responses.

HTTP Status Codes

CodeMeaning
200Success
400Bad request (missing prompt, no eligible routes)
401Unauthorized (admin routes without auth)
403Forbidden (wrong domain)
500Server error (no routes configured)
502All providers failed

Error Response Format

{
  "error": "Error message describing what went wrong"
}