Use this file to discover all available pages before exploring further.
Add Portkey to Open WebUI to get:
Unified access to 1600+ LLMs through a single API
Real-time cost tracking and per-user attribution
Enterprise governance with budget limits and access controls
Reliability features like fallbacks, caching, and retries
Important: Open WebUI doesn’t support custom headers, so you can’t pass x-portkey-config per request.Solution: Attach a default config to your Portkey API key. All requests with that key automatically use the config. For different configs per user/use case, create separate API keys. See Default Configs.
The Manifold Pipe solves a critical enterprise problem: per-user attribution with shared API keys.In typical deployments, a shared API key means all requests appear anonymous in logs. The Manifold Pipe automatically forwards Open WebUI user context (email, name, role) to Portkey, enabling true per-user cost tracking and governance.
Per-User Attribution
Track which user made each request—even with shared API keys.
Structured Metadata
Forward user context (email, name, role, chat ID) for filtering and analytics.
Auto Model Discovery
Automatically populate model dropdown from your Model Catalog.
"""title: Portkey Manifold Pipeauthor: Portkeyversion: 0.8.0license: MITdocumentation: https://portkey.ai/docs/integrations/libraries/openwebui"""from pydantic import BaseModel, Fieldfrom typing import Union, Generator, Iteratorimport jsonimport requestsclass Pipe: class Valves(BaseModel): PORTKEY_API_KEY: str = Field( default="", description="Your Portkey API key (required).", ) PORTKEY_API_BASE_URL: str = Field( default="https://api.portkey.ai/v1", description="Base URL for Portkey API.", ) AUTO_DISCOVER_MODELS: bool = Field( default=True, description="Auto-fetch models from Portkey.", ) PORTKEY_MODELS: str = Field( default="@openai-slug/gpt-4o, @anthropic-slug/claude-sonnet-latest", description="Comma-separated model IDs (used when auto-discovery is off or as fallback).", ) def __init__(self): self.type = "manifold" self.valves = self.Valves() self.name = "PORTKEY" def pipes(self) -> list: model_ids = [] # Auto-discover models from Portkey if self.valves.AUTO_DISCOVER_MODELS and self.valves.PORTKEY_API_KEY: try: r = requests.get( f"{self.valves.PORTKEY_API_BASE_URL}/models", headers={"Authorization": f"Bearer {self.valves.PORTKEY_API_KEY}"}, timeout=10, ) if r.status_code == 200: data = r.json().get("data", []) model_ids = [ m["id"] for m in data if isinstance(m, dict) and "id" in m ] except: pass # Fallback to manual list # Add manual models if self.valves.PORTKEY_MODELS: manual = [ m.strip() for m in self.valves.PORTKEY_MODELS.split(",") if m.strip() ] model_ids.extend(manual) # Deduplicate seen = set() unique = [] for m in model_ids: if m not in seen: seen.add(m) unique.append(m) return [{"id": m, "name": m} for m in unique] def pipe(self, body: dict, __user__: dict) -> Union[str, Generator, Iterator]: if not self.valves.PORTKEY_API_KEY: raise Exception("PORTKEY_API_KEY is required.") # Clean model ID (remove Open WebUI prefix) full_model_id = body.get("model", "") actual_model_id = ( full_model_id.split(".", 1)[-1] if "." in full_model_id else full_model_id ) payload = {**body, "model": actual_model_id} # Build headers with metadata headers = { "Authorization": f"Bearer {self.valves.PORTKEY_API_KEY}", "Content-Type": "application/json", } metadata = {} if __user__: if "email" in __user__: metadata["_user"] = __user__["email"] # Special key for User column metadata["email"] = __user__["email"] if "name" in __user__: metadata["name"] = __user__["name"] if "id" in __user__: metadata["user_id"] = __user__["id"] if "role" in __user__: metadata["role"] = __user__["role"] if "chat_id" in __user__: metadata["chat_id"] = __user__["chat_id"] if metadata: headers["x-portkey-metadata"] = json.dumps(metadata) try: r = requests.post( url=f"{self.valves.PORTKEY_API_BASE_URL}/chat/completions", json=payload, headers=headers, stream=body.get("stream", True), ) r.raise_for_status() return r.iter_lines() if body.get("stream", True) else r.json() except requests.HTTPError as e: error_msg = f"Portkey API Error: {e.response.status_code}" try: error_details = e.response.json() error_msg += f" - {json.dumps(error_details)}" except: pass raise Exception(error_msg) except Exception as e: raise Exception(f"Error: {str(e)}")
User emails appear directly in the User column of your logs—no need to click into individual entries.
Captured metadata: User email, name, role, chat ID, user ID. Filter logs by user, attribute costs to departments, maintain audit trails—all without individual API keys per user.
Open WebUI (User A, User B, User C...) ↓Shared Portkey API Key ↓ Portkey Logs: All requests appear anonymous❌ No cost attribution, usage tracking, or audit trails
The pipe uses Open WebUI’s __user__ context object and formats it as Portkey metadata.