diff --git a/.gitignore b/.gitignore
index 85bb2101..1a2c8977 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,4 @@ yarn-error.log*
# test reports
/playwright-report
/test-results
+.firecrawl
\ No newline at end of file
diff --git a/docs/platform/aihosting/70-dedicated/10-getting-started.mdx b/docs/platform/aihosting/70-dedicated/10-getting-started.mdx
new file mode 100644
index 00000000..929e2bab
--- /dev/null
+++ b/docs/platform/aihosting/70-dedicated/10-getting-started.mdx
@@ -0,0 +1,187 @@
+---
+sidebar_label: Getting started
+description: How to make your first request to your dedicated AI hosting endpoint
+title: Getting started with Dedicated AI Hosting
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+After we set up your dedicated instance, you will receive:
+
+- **API base URL** - your dedicated HTTPS endpoint, e.g. `https://your-company.llm.aihosting.mittwald.de`
+- **API key** - a bearer token that authenticates your requests
+
+Keep your API key confidential. Store it in an environment variable or secrets manager — never hardcode it in source files or commit it to version control. If a key is exposed, contact us to rotate it.
+
+## Checking available models {#list-models}
+
+```shellsession
+user@local $ curl https://your-company.llm.aihosting.mittwald.de/v1/models \
+ -H "Authorization: Bearer YOUR_API_KEY"
+```
+
+Use one of the returned model IDs as `YOUR_MODEL_ID` in requests.
+
+:::note
+If no model has been installed for your endpoint yet, this list can be empty. In that case, contact us to complete model provisioning before sending inference requests.
+:::
+
+## Sending your first request {#first-request}
+
+
+
+
+```shellsession
+user@local $ curl https://your-company.llm.aihosting.mittwald.de/v1/chat/completions \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "YOUR_MODEL_ID",
+ "messages": [
+ {"role": "user", "content": "Explain retrieval-augmented generation in two sentences."}
+ ]
+ }'
+```
+
+
+
+
+```shellsession
+user@local $ pip install openai python-dotenv
+```
+
+```env
+OPENAI_API_KEY=YOUR_API_KEY
+OPENAI_BASE_URL=https://your-company.llm.aihosting.mittwald.de/v1
+```
+
+```python
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI()
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[
+ {"role": "user", "content": "Explain retrieval-augmented generation in two sentences."}
+ ]
+)
+
+print(response.choices[0].message.content)
+```
+
+
+
+
+```shellsession
+user@local $ npm install openai dotenv
+```
+
+```env
+OPENAI_API_KEY=YOUR_API_KEY
+OPENAI_BASE_URL=https://your-company.llm.aihosting.mittwald.de/v1
+```
+
+```typescript
+import OpenAI from "openai";
+import "dotenv/config";
+
+const client = new OpenAI({
+ apiKey: process.env.OPENAI_API_KEY,
+ baseURL: process.env.OPENAI_BASE_URL,
+});
+
+const response = await client.chat.completions.create({
+ model: "YOUR_MODEL_ID",
+ messages: [
+ { role: "user", content: "Explain retrieval-augmented generation in two sentences." }
+ ],
+});
+
+console.log(response.choices[0].message.content);
+```
+
+
+
+
+## Streaming responses {#streaming}
+
+Add `"stream": true` to receive tokens as they are generated instead of waiting for the full response.
+
+
+
+
+```shellsession
+user@local $ curl https://your-company.llm.aihosting.mittwald.de/v1/chat/completions \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "YOUR_MODEL_ID",
+ "stream": true,
+ "messages": [
+ {"role": "user", "content": "Explain retrieval-augmented generation in two sentences."}
+ ]
+ }'
+```
+
+
+
+
+```python
+from openai import OpenAI
+
+client = OpenAI(api_key="YOUR_API_KEY", base_url="https://your-company.llm.aihosting.mittwald.de/v1")
+
+with client.chat.completions.stream(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "Explain retrieval-augmented generation in two sentences."}],
+) as stream:
+ for chunk in stream:
+ if chunk.choices[0].delta.content:
+ print(chunk.choices[0].delta.content, end="", flush=True)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "YOUR_API_KEY",
+ baseURL: "https://your-company.llm.aihosting.mittwald.de/v1",
+});
+
+const stream = await client.chat.completions.create({
+ model: "YOUR_MODEL_ID",
+ stream: true,
+ messages: [{ role: "user", content: "Explain retrieval-augmented generation in two sentences." }],
+});
+
+for await (const chunk of stream) {
+ process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
+}
+```
+
+
+
+
+:::note
+If a streaming request is interrupted mid-response (for example, a network timeout or a server restart), the connection closes rather than returning an HTTP error code. The HTTP 200 is written when the stream starts, so a mid-stream failure looks like a connection reset on the client side. Handle this by detecting an incomplete stream and retrying the request.
+:::
+
+## Request parameters {#parameters}
+
+Parameter recommendations can be model-specific. Use the defaults from your chosen SDK first, then tune based on your model behavior and use case.
+
+## Drop-in replacement {#drop-in}
+
+Because the endpoint is OpenAI-compatible, you can use it as a drop-in replacement in frameworks that accept a custom base URL. See [OpenAI API compatibility](../openai-compatibility) for the full list of supported endpoints and parameters, including tool calling and structured outputs.
+
+## Managing multiple API keys {#key-management}
+
+If you want separate keys per app/team, usage tracking, or per-key rate limits, run [LiteLLM](../litellm) as a self-hosted proxy.
diff --git a/docs/platform/aihosting/70-dedicated/20-litellm.mdx b/docs/platform/aihosting/70-dedicated/20-litellm.mdx
new file mode 100644
index 00000000..539b246d
--- /dev/null
+++ b/docs/platform/aihosting/70-dedicated/20-litellm.mdx
@@ -0,0 +1,304 @@
+---
+sidebar_label: Key management with LiteLLM
+description: Run LiteLLM as a self-hosted gateway for API key lifecycle, budgets, limits, and usage analytics
+title: End-to-end key management with LiteLLM
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+Your dedicated endpoint includes one upstream API key. LiteLLM lets you turn this into a full customer-facing key management layer: issue keys per app/team/user, set limits, revoke access, and track usage.
+
+This is especially useful for German web and creative agencies that operate multiple customer projects and need clear tenant separation.
+
+## What LiteLLM adds {#what-it-adds}
+
+- Virtual keys per application, team, or end customer
+- Per-key limits (requests/min, tokens/min, budgets)
+- Key lifecycle controls (block, unblock, rotate, expire)
+- Usage and spend visibility by key, user, and team
+- Admin UI plus API for automation
+
+## Prerequisites {#prerequisites}
+
+- Docker and Docker Compose
+- Your dedicated mittwald endpoint and upstream API key
+- A PostgreSQL database (required for persistent key management)
+
+## A-to-Z setup {#setup}
+
+### 1. Create a `.env` file {#setup-env}
+
+```env
+LITELLM_MASTER_KEY=sk-change-this-master-key
+UPSTREAM_BASE_URL=https://your-company.llm.aihosting.mittwald.de
+UPSTREAM_API_KEY=YOUR_DEDICATED_API_KEY
+POSTGRES_USER=litellm
+POSTGRES_PASSWORD=change-this-db-password
+POSTGRES_DB=litellm
+UI_USERNAME=admin
+UI_PASSWORD=change-this-ui-password
+```
+
+### 2. Create `litellm_config.yaml` {#setup-config}
+
+```yaml
+model_list:
+ - model_name: YOUR_MODEL_ID
+ litellm_params:
+ model: openai/YOUR_MODEL_ID
+ api_base: os.environ/UPSTREAM_BASE_URL
+ api_key: os.environ/UPSTREAM_API_KEY
+
+general_settings:
+ master_key: os.environ/LITELLM_MASTER_KEY
+ database_url: os.environ/DATABASE_URL
+```
+
+### 3. Create `docker-compose.yml` {#setup-compose}
+
+```yaml
+services:
+ postgres:
+ image: postgres:16
+ environment:
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: ${POSTGRES_DB}
+ volumes:
+ - litellm-postgres:/var/lib/postgresql/data
+
+ litellm:
+ image: docker.litellm.ai/berriai/litellm:main-latest
+ depends_on:
+ - postgres
+ ports:
+ - "4000:4000"
+ environment:
+ LITELLM_MASTER_KEY: ${LITELLM_MASTER_KEY}
+ UPSTREAM_BASE_URL: ${UPSTREAM_BASE_URL}
+ UPSTREAM_API_KEY: ${UPSTREAM_API_KEY}
+ DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
+ volumes:
+ - ./litellm_config.yaml:/app/config.yaml
+ command: ["--config", "/app/config.yaml"]
+
+volumes:
+ litellm-postgres:
+```
+
+### 4. Start services {#setup-start}
+
+```shellsession
+user@local $ docker compose up -d
+```
+
+### 5. Verify gateway + model passthrough {#setup-verify}
+
+```shellsession
+user@local $ curl http://localhost:4000/v1/models \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}"
+```
+
+Open `http://localhost:4000/ui` and sign in with the `UI_USERNAME` / `UI_PASSWORD` you set in your `.env` file. The Admin UI starts automatically alongside the proxy — no additional flag needed.
+
+## Key lifecycle operations (API) {#key-lifecycle}
+
+The key-management endpoints are documented in LiteLLM's Virtual Keys docs and Swagger.
+
+### Create a virtual key {#create-key}
+
+```shellsession
+user@local $ curl http://localhost:4000/key/generate \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "models": ["YOUR_MODEL_ID"],
+ "key_alias": "team-a-prod",
+ "metadata": {"owner": "team-a"},
+ "tpm_limit": 120000,
+ "rpm_limit": 300,
+ "max_budget": 250
+ }'
+```
+
+### Inspect key usage and limits {#key-info}
+
+```shellsession
+user@local $ curl "http://localhost:4000/key/info?key=sk-virtual-key" \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}"
+```
+
+Some deployments also expose versioned info routes (`/v2/key/info`) in Swagger.
+
+### Block a key immediately {#key-block}
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/block \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"key":"sk-virtual-key"}'
+```
+
+### Unblock a key {#key-unblock}
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/unblock \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"key":"sk-virtual-key"}'
+```
+
+### Rotate a key {#key-rotate}
+
+Key rotation is done by creating a new key with the same settings and then deleting the old one. First generate a replacement:
+
+```shellsession
+user@local $ curl http://localhost:4000/key/generate \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "models": ["YOUR_MODEL_ID"],
+ "key_alias": "team-a-prod-v2",
+ "metadata": {"owner": "team-a"}
+ }'
+```
+
+Then delete the old key:
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/delete \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"keys":["sk-old-virtual-key"]}'
+```
+
+### Revoke permanently {#key-revoke}
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/delete \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"keys":["sk-virtual-key"]}'
+```
+
+## Admin UI {#ui}
+
+The Admin UI is available at `http://localhost:4000/ui`. Sign in with the credentials you set via `UI_USERNAME` and `UI_PASSWORD` in your `.env` file.
+
+The Swagger API reference (all proxy endpoints) is available at `http://localhost:4000/`.
+
+### Keys {#ui-keys}
+
+The **Keys** section shows all virtual keys with their current spend, limits, and status.
+
+Actions available:
+
+| Action | What it does |
+|--------|-------------|
+| Create key | Set alias, model allowlist, TPM/RPM limits, max budget, expiry date, team/user assignment |
+| Edit key | Update limits, budget, and metadata without recreating the key |
+| Block key | Immediately cut off access — requests with this key return 401 |
+| Unblock key | Restore access |
+| Delete key | Permanently revoke — cannot be undone |
+
+### Spend and usage dashboard {#ui-spend}
+
+The dashboard shows spend and request volume broken down by:
+
+- **Per key** — how much each virtual key has spent
+- **Per user** — spend for each user ID you assigned to keys
+- **Per team** — aggregate spend across all keys belonging to a team
+
+Spend resets are available from the API (`POST /global/spend/reset`) for admin use.
+
+### Teams {#ui-teams}
+
+Teams group keys and users under a shared budget and model allowlist. Create a team, then assign keys to it when generating them. The team dashboard shows aggregate spend and key activity.
+
+### Users {#ui-users}
+
+The **Users** section shows all users with assigned keys and their spend. You can create users and assign them to teams. Users can optionally be invited to log into the UI themselves with their own credentials (self-serve key management — they can only manage their own keys).
+
+### Models {#ui-models}
+
+The **Models** section lets you add or modify models available through the proxy — no proxy restart required. Pricing data can be synced from GitHub to keep cost calculations current.
+
+## Usage statistics and spend control {#statistics}
+
+LiteLLM tracks usage and spend on proxy requests and exposes:
+
+- Per key: usage/spend (`/key/info`)
+- Per user/team: user and team info endpoints
+- Dashboard views for traffic, limits, and key activity
+
+## Reselling dedicated capacity to your own customers {#reselling}
+
+This setup is suitable for reseller scenarios. Your customers can use your AI product while the upstream mittwald dedicated key remains private.
+
+Recommended reseller pattern:
+
+1. Keep the upstream dedicated key only inside LiteLLM
+2. Issue one virtual key per customer/app/environment
+3. Apply per-key limits and budgets according to plan tier
+4. Use block/unblock/rotate/delete for lifecycle control
+
+This gives you tenant-level billing and control without exposing upstream credentials.
+
+For agency business models, this maps well to:
+
+- one virtual key per client project
+- separate quotas for staging vs production
+- contract-driven limits per customer tier
+
+## Use virtual keys in client apps {#clients}
+
+
+
+
+```env
+OPENAI_BASE_URL=http://localhost:4000/v1
+OPENAI_API_KEY=sk-virtual-key
+```
+
+
+
+
+```python
+from openai import OpenAI
+
+client = OpenAI(api_key="sk-virtual-key", base_url="http://localhost:4000/v1")
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "Hello"}],
+)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "sk-virtual-key",
+ baseURL: "http://localhost:4000/v1",
+});
+```
+
+
+
+
+## Operational recommendations {#ops}
+
+- Keep LiteLLM and database persistent (no in-memory-only setup in production)
+- Use strong, rotated admin credentials (`master_key`)
+- Restrict admin surface and expose UI only where needed
+- Validate key policies with test keys before customer onboarding
+
+## References {#references}
+
+- [LiteLLM Virtual Keys](https://docs.litellm.ai/docs/proxy/virtual_keys)
+- [LiteLLM Admin UI](https://docs.litellm.ai/docs/proxy/ui)
+- [LiteLLM Swagger / Endpoints](https://www.litellm.org/)
diff --git a/docs/platform/aihosting/70-dedicated/30-bifrost.mdx b/docs/platform/aihosting/70-dedicated/30-bifrost.mdx
new file mode 100644
index 00000000..a7bbe04d
--- /dev/null
+++ b/docs/platform/aihosting/70-dedicated/30-bifrost.mdx
@@ -0,0 +1,292 @@
+---
+sidebar_label: AI gateway with Bifrost
+description: Run Bifrost as a self-hosted gateway in front of your dedicated endpoint
+title: End-to-end AI gateway setup with Bifrost
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+Bifrost is an AI gateway for routing, failover, and provider governance. In a dedicated setup, Bifrost sits between your apps and your dedicated mittwald endpoint.
+
+For creative/web agencies, Bifrost helps centralize routing across client workloads, campaign spikes, and mixed provider landscapes.
+
+## When to use Bifrost vs LiteLLM {#when-to-use}
+
+- Use **LiteLLM** for virtual end-user key lifecycle, budgets, and spend views.
+- Use **Bifrost** for provider routing, fallback chains, and gateway-level policy.
+- Many teams run both: LiteLLM for customer keys, Bifrost for upstream routing.
+
+## Prerequisites {#prerequisites}
+
+- Docker installed
+- Dedicated endpoint URL and API key from mittwald
+
+## A-to-Z setup {#setup}
+
+### 1. Start Bifrost {#setup-start}
+
+```shellsession
+user@local $ docker run -d \
+ --name bifrost \
+ -p 8080:8080 \
+ -v "$(pwd)/data:/app/data" \
+ maximhq/bifrost
+```
+
+Open `http://localhost:8080`.
+
+### 2. Register your dedicated endpoint as a provider {#setup-register}
+
+Provider registration and key registration are two separate API calls.
+
+**Step 1 — register the provider** (sets base URL and network config):
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "provider": "openai",
+ "network_config": {
+ "base_url": "https://your-company.llm.aihosting.mittwald.de/v1"
+ }
+ }'
+```
+
+**Step 2 — add your API key to the provider**:
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers/openai/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "name": "mittwald-dedicated",
+ "value": "YOUR_DEDICATED_API_KEY",
+ "models": ["*"],
+ "weight": 1.0
+ }'
+```
+
+### 3. Validate provider config in UI {#setup-validate}
+
+In **Model Providers**, check:
+
+- Key is active
+- Model mapping is correct (`*` or explicit list)
+- Base URL points to your dedicated endpoint
+
+### 4. Send traffic through Bifrost {#setup-traffic}
+
+
+
+
+```shellsession
+user@local $ curl http://localhost:8080/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "openai/YOUR_MODEL_ID",
+ "messages": [
+ {"role": "user", "content": "Hello"}
+ ]
+ }'
+```
+
+
+
+
+```python
+from openai import OpenAI
+
+client = OpenAI(api_key="dummy", base_url="http://localhost:8080/openai/v1")
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "Hello"}],
+)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "dummy",
+ baseURL: "http://localhost:8080/openai/v1",
+});
+```
+
+
+
+
+## Routing to mittwald shared AI Hosting (in addition to dedicated) {#shared-routing}
+
+If you also use mittwald shared AI Hosting, add it as another OpenAI-compatible provider.
+
+Shared AI Hosting base URL:
+
+- `https://llm.aihosting.mittwald.de/v1`
+
+Example — register and add a key:
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "provider": "mittwald-shared",
+ "network_config": {
+ "base_url": "https://llm.aihosting.mittwald.de/v1"
+ },
+ "custom_provider_config": {
+ "base_provider_type": "openai"
+ }
+ }'
+
+curl --location 'http://localhost:8080/api/providers/mittwald-shared/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "name": "mittwald-shared-key",
+ "value": "YOUR_SHARED_API_KEY",
+ "models": ["*"],
+ "weight": 1.0
+ }'
+```
+
+## Routing rules: when to send traffic to dedicated vs shared {#routing-rules}
+
+Bifrost routing decisions are typically built from:
+
+- model-to-key mapping (`models` per key)
+- weighted distribution (`weight`)
+- fallback ordering (primary provider, secondary provider)
+
+Recommended rules:
+
+1. Premium/contracted workloads -> dedicated provider key
+2. burst or long-tail workloads -> shared provider key
+3. fallback path -> dedicated first, shared second (or inverse, depending on SLO/cost goals)
+
+Example model-specific split:
+
+- Key `dedicated-key`: `models: ["YOUR_PREMIUM_MODEL_ID"]`
+- Key `shared-key`: `models: ["*"]` (or explicit non-premium list)
+
+This keeps high-value traffic on reserved capacity while still allowing scale-out via shared hosting.
+
+You can also add other providers (for example Anthropic / Claude) and route specific workloads there.
+
+Example additional provider:
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "provider": "anthropic"
+ }'
+
+curl --location 'http://localhost:8080/api/providers/anthropic/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "name": "claude-key",
+ "value": "YOUR_ANTHROPIC_API_KEY",
+ "models": ["claude-3-7-sonnet", "claude-4-sonnet"],
+ "weight": 1.0
+ }'
+```
+
+## Agency-oriented routing scenarios {#agency-scenarios}
+
+Typical agency setup in Germany:
+
+- multiple client websites/apps
+- mixed workloads (chatbot, content generation, backoffice automation)
+- changing traffic patterns (campaign launches, seasonal peaks)
+
+Recommended policy examples:
+
+- keep premium client workloads on dedicated capacity
+- send non-critical or burst traffic to shared capacity
+- route specific tasks (for example copywriting/review workflows) to Claude if needed
+- keep one fallback route active for outage resilience
+
+This lets agencies offer stable SLAs for key customers while keeping total operating cost predictable.
+
+## Complete multi-lane routing example {#full-example}
+
+This example sets up three lanes in one sequence: dedicated mittwald capacity as the primary lane, shared mittwald capacity as a burst/fallback lane, and Anthropic as a separate lane for specific tasks. Copy and adapt the three provider registrations, then route by model name.
+
+```shellsession
+# Lane 1: dedicated mittwald endpoint (primary, reserved capacity)
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{"provider": "openai", "network_config": {"base_url": "https://your-company.llm.aihosting.mittwald.de/v1"}}'
+
+user@local $ curl --location 'http://localhost:8080/api/providers/openai/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{"name": "mittwald-dedicated", "value": "YOUR_DEDICATED_API_KEY", "models": ["YOUR_PREMIUM_MODEL_ID"], "weight": 1.0}'
+
+# Lane 2: shared mittwald endpoint (burst and long-tail workloads)
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{"provider": "mittwald-shared", "network_config": {"base_url": "https://llm.aihosting.mittwald.de/v1"}, "custom_provider_config": {"base_provider_type": "openai"}}'
+
+user@local $ curl --location 'http://localhost:8080/api/providers/mittwald-shared/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{"name": "mittwald-shared-key", "value": "YOUR_SHARED_API_KEY", "models": ["*"], "weight": 1.0}'
+
+# Lane 3: Anthropic (for specific task types routed by model name)
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{"provider": "anthropic"}'
+
+user@local $ curl --location 'http://localhost:8080/api/providers/anthropic/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{"name": "claude-key", "value": "YOUR_ANTHROPIC_API_KEY", "models": ["claude-3-7-sonnet", "claude-4-sonnet"], "weight": 1.0}'
+```
+
+After registration, send requests to the correct lane by using the matching model name:
+
+- `YOUR_PREMIUM_MODEL_ID` → hits dedicated lane
+- any model matched by `*` on shared → hits shared lane
+- `claude-3-7-sonnet` or `claude-4-sonnet` → hits Anthropic lane
+
+Fallback behavior (dedicated → shared) activates automatically if the primary provider key is unreachable. Adjust `weight` values to control traffic distribution.
+
+## Production configuration patterns {#production-patterns}
+
+### Provider-level failover and load split {#production-failover}
+
+- Add multiple keys/providers
+- Use `weight` to distribute traffic
+- Use model-specific key mapping for premium/basic lanes
+
+### Self-hosted endpoint hardening {#production-hardening}
+
+- Use explicit model allowlists instead of `*` where possible
+- Configure network timeouts in provider `network_config`
+- Use internal DNS/FQDN for Kubernetes cross-namespace routing
+
+### Logging and observability {#production-logging}
+
+Enable provider-level request/response logging options in Bifrost only if required by your compliance profile.
+
+## Combining with LiteLLM (recommended for customer keys) {#combination}
+
+A robust pattern is:
+
+1. Customer apps -> LiteLLM virtual keys
+2. LiteLLM upstream -> Bifrost
+3. Bifrost -> your dedicated endpoint
+
+This gives:
+
+- Customer key lifecycle and spend controls
+- Gateway routing/fallback policies
+- Clear separation of concerns
+
+## References {#references}
+
+- [Bifrost Setting Up](https://docs.getbifrost.ai/quickstart/gateway/setting-up)
+- [Bifrost Provider Configuration](https://docs.getbifrost.ai/quickstart/gateway/provider-configuration)
+- [Bifrost OpenAI SDK Integration](https://docs.getbifrost.ai/integrations/openai-sdk/overview)
+- [LiteLLM key management guide](../litellm)
diff --git a/docs/platform/aihosting/70-dedicated/40-error-handling.mdx b/docs/platform/aihosting/70-dedicated/40-error-handling.mdx
new file mode 100644
index 00000000..98d88f4d
--- /dev/null
+++ b/docs/platform/aihosting/70-dedicated/40-error-handling.mdx
@@ -0,0 +1,108 @@
+---
+sidebar_label: Error handling and retries
+description: HTTP error codes, retry guidance, and capacity behavior for the dedicated AI Hosting endpoint
+title: Error handling and retries
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+This page covers the HTTP error codes your application may receive, how to handle capacity behavior, and how to configure retries correctly for the dedicated endpoint.
+
+## HTTP error codes {#error-codes}
+
+| Code | Meaning | What to do |
+|------|---------|------------|
+| `400` | Bad request — input too long or malformed | Reduce input length or fix request format (see context limit below) |
+| `401` | Invalid or missing API key | Check `Authorization: Bearer YOUR_API_KEY` header |
+| `503` | Service temporarily unavailable — endpoint overloaded or restarting | Retry with exponential backoff |
+| `500` | Internal server error | Retry with backoff; contact support if it persists |
+| `502` | Bad gateway | Retry with backoff |
+| `504` | Gateway timeout — request took too long | Reduce input size, lower concurrency, or retry |
+
+:::note 401 response format
+The `401` response body is `{"error": "Unauthorized"}`. This is simpler than the standard OpenAI error object format and does not include `type`, `param`, or `code` fields. Check your error handling code accordingly.
+:::
+
+## Context length limit {#context-limit}
+
+Requests whose total token count (prompt + completion) exceeds the model's configured context window are rejected with `400`. The response uses the OpenAI error object format:
+
+```json
+{
+ "object": "error",
+ "message": "This model's maximum context length is X tokens. However, you requested Y tokens ...",
+ "type": "invalid_request_error",
+ "param": "messages",
+ "code": 400
+}
+```
+
+Check the context window for your provisioned model in the [Getting started guide](../getting-started) via the `/v1/models` endpoint. Plan your input + expected output to stay within that limit.
+
+## Request body size limit {#body-size}
+
+The maximum request body size is **25 MB**. Requests exceeding this are rejected before reaching the model. This limit is only relevant for multimodal inputs (for example, base64-encoded images). Standard text chat requests are far below this limit.
+
+## What to expect under heavy load {#capacity}
+
+The endpoint queues requests internally when all compute slots are occupied. This means:
+
+- Requests do not immediately fail when the model is busy — they wait in the queue.
+- Under very high sustained load, queued requests may eventually time out. The connection closes as a connection reset rather than returning an HTTP error code. This is most visible with streaming responses (see [Streaming and mid-stream failures](#streaming-failures) below).
+- The endpoint returns `503` when it cannot accept new requests at all (for example, during a restart or on a true server error).
+
+If you regularly experience high latency or timeouts under your expected load, contact us to review your provisioned capacity.
+
+## Retry guidance {#retries}
+
+Retry on `503`, `502`, `500`. Do not retry on `400` or `401`.
+
+Recommended retry pattern:
+
+1. On `5xx`: wait, then retry
+2. Start with a **1-second wait**
+3. Double the wait on each subsequent attempt (exponential backoff)
+4. Cap the wait at **60 seconds**
+5. Stop after **5 attempts**
+
+Most OpenAI-compatible client libraries have built-in retry logic you can configure directly:
+
+
+
+
+```python
+import openai
+
+client = openai.OpenAI(
+ api_key="YOUR_API_KEY",
+ base_url="https://your-company.llm.aihosting.mittwald.de/v1",
+ max_retries=5,
+)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "YOUR_API_KEY",
+ baseURL: "https://your-company.llm.aihosting.mittwald.de/v1",
+ maxRetries: 5,
+});
+```
+
+
+
+
+## Streaming and mid-stream failures {#streaming-failures}
+
+For streaming requests (`"stream": true`), the HTTP `200` response header is written when the first token is ready. If a failure occurs mid-stream (for example, a timeout or a server restart), the connection closes rather than returning an HTTP error code.
+
+Detect this by checking whether the stream ended with the expected stop reason. Retry the full request if not.
+
+## Protocol support {#protocol}
+
+The endpoint supports **HTTPS only**. gRPC is not available.
diff --git a/docs/platform/aihosting/70-dedicated/50-openai-compatibility.mdx b/docs/platform/aihosting/70-dedicated/50-openai-compatibility.mdx
new file mode 100644
index 00000000..647fb886
--- /dev/null
+++ b/docs/platform/aihosting/70-dedicated/50-openai-compatibility.mdx
@@ -0,0 +1,186 @@
+---
+sidebar_label: OpenAI compatibility
+description: Which OpenAI API endpoints and parameters are supported on the dedicated AI Hosting endpoint
+title: OpenAI API compatibility
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+The dedicated AI Hosting endpoint is OpenAI-compatible. You can point any OpenAI SDK or library at it by changing two values — the base URL and the API key. This page documents exactly what is supported, what is not, and where the behavior differs from OpenAI's hosted service.
+
+## Switching from OpenAI {#migration}
+
+```python
+# Before
+client = OpenAI(api_key="sk-...")
+
+# After
+client = OpenAI(
+ api_key="YOUR_DEDICATED_API_KEY",
+ base_url="https://your-company.llm.aihosting.mittwald.de/v1",
+)
+```
+
+The model name also changes. Use the ID returned by `/v1/models` instead of an OpenAI model name like `gpt-4o`.
+
+## Supported endpoints {#endpoints}
+
+| Endpoint | Supported |
+|----------|-----------|
+| `GET /v1/models` | ✅ |
+| `POST /v1/chat/completions` | ✅ |
+| `POST /v1/completions` | ✅ (legacy text completions) |
+| `POST /v1/responses` | ✅ |
+| `POST /v1/embeddings` | ❌ — this endpoint serves a generative model, not an embedding model |
+| Assistants API (`/v1/assistants`, `/v1/threads`, …) | ❌ |
+| Batch API (`/v1/batches`) | ❌ |
+| Fine-tuning API (`/v1/fine_tuning`) | ❌ |
+| Files API (`/v1/files`) | ❌ |
+| Moderations API (`/v1/moderations`) | ❌ |
+| Audio / image endpoints | ❌ |
+
+## /v1/chat/completions parameter support {#parameters}
+
+| Parameter | Support | Notes |
+|-----------|---------|-------|
+| `model` | ✅ | Use the model ID from `/v1/models` |
+| `messages` | ✅ | |
+| `stream` | ✅ | See [Streaming](../getting-started#streaming) |
+| `temperature`, `top_p` | ✅ | |
+| `max_tokens` / `max_completion_tokens` | ✅ | |
+| `stop` | ✅ | |
+| `n` | ✅ | Multiple completions per request |
+| `presence_penalty`, `frequency_penalty` | ✅ | |
+| `logprobs`, `top_logprobs` | ✅ | |
+| `tools`, `tool_choice` | ✅ | See [Tool calling](#tool-calling) |
+| `parallel_tool_calls` | ✅ | `false` limits to one tool call; `true` (default) allows multiple |
+| `response_format` | ✅ | See [Structured outputs](#structured-outputs) |
+| `seed` | ⚠️ | Accepted and passed through — reproducibility is best-effort due to GPU non-determinism |
+| `user` | ⚠️ | Accepted but ignored |
+| `logit_bias` | ✅ | Supported; token IDs outside the model vocabulary return a validation error |
+| `stream_options` | ✅ | Supported when `stream: true`; passing it without streaming returns a validation error. `include_usage: true` appends a usage chunk at the end of the stream |
+
+## Structured outputs {#structured-outputs}
+
+Both JSON mode and JSON schema mode are supported.
+
+**JSON object mode** — constrains output to valid JSON:
+
+```json
+{
+ "model": "YOUR_MODEL_ID",
+ "messages": [{"role": "user", "content": "Return a JSON object with keys name and age."}],
+ "response_format": {"type": "json_object"}
+}
+```
+
+**JSON schema mode** — constrains output to a specific schema:
+
+```json
+{
+ "model": "YOUR_MODEL_ID",
+ "messages": [{"role": "user", "content": "Extract the person's name and age."}],
+ "response_format": {
+ "type": "json_schema",
+ "json_schema": {
+ "name": "person",
+ "strict": true,
+ "schema": {
+ "type": "object",
+ "properties": {
+ "name": {"type": "string"},
+ "age": {"type": "integer"}
+ },
+ "required": ["name", "age"],
+ "additionalProperties": false
+ }
+ }
+ }
+}
+```
+
+:::note
+JSON schema mode uses guided decoding. Complex recursive schemas or very large schemas may increase latency.
+:::
+
+## Tool calling {#tool-calling}
+
+Tool calling (function calling) follows the OpenAI format. Pass your tools in the `tools` array and set `tool_choice` to control behavior.
+
+```python
+from openai import OpenAI
+
+client = OpenAI(
+ api_key="YOUR_API_KEY",
+ base_url="https://your-company.llm.aihosting.mittwald.de/v1",
+)
+
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "Get the current weather for a location.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "City and country"},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+]
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "What is the weather in Berlin?"}],
+ tools=tools,
+ tool_choice="auto",
+)
+
+tool_calls = response.choices[0].message.tool_calls
+```
+
+`parallel_tool_calls=False` restricts the model to at most one tool call per turn, which simplifies handling in multi-step agent loops.
+
+## Configuring client timeouts {#timeouts}
+
+LLM requests with long inputs or outputs can take 60 seconds or more. Many HTTP clients and frameworks default to much shorter timeouts. Set your client timeout explicitly to avoid spurious failures.
+
+
+
+
+```python
+import httpx
+from openai import OpenAI
+
+client = OpenAI(
+ api_key="YOUR_API_KEY",
+ base_url="https://your-company.llm.aihosting.mittwald.de/v1",
+ timeout=httpx.Timeout(300.0, connect=10.0),
+)
+```
+
+A 300-second (5-minute) read timeout covers most inference workloads. Increase for very long contexts or high-concurrency conditions.
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "YOUR_API_KEY",
+ baseURL: "https://your-company.llm.aihosting.mittwald.de/v1",
+ timeout: 300 * 1000, // 300 seconds in milliseconds
+});
+```
+
+
+
+
+:::note
+The server-side connection timeout is 30 minutes. Client timeouts shorter than your longest expected request will cause client-side failures before the server terminates the connection.
+:::
diff --git a/docs/platform/aihosting/70-dedicated/_category_.yml b/docs/platform/aihosting/70-dedicated/_category_.yml
new file mode 100644
index 00000000..086773ba
--- /dev/null
+++ b/docs/platform/aihosting/70-dedicated/_category_.yml
@@ -0,0 +1,4 @@
+label: Dedicated AI Hosting
+link:
+ type: doc
+ id: platform/aihosting/dedicated/index
diff --git a/docs/platform/aihosting/70-dedicated/index.mdx b/docs/platform/aihosting/70-dedicated/index.mdx
new file mode 100644
index 00000000..671268ed
--- /dev/null
+++ b/docs/platform/aihosting/70-dedicated/index.mdx
@@ -0,0 +1,226 @@
+---
+sidebar_label: Overview
+description: Dedicated AI Hosting - exclusive GPU capacity for demanding AI workloads
+title: Dedicated AI Hosting
+---
+
+import DocCardList from "@theme/DocCardList";
+
+Dedicated AI Hosting gives you exclusive access to reserved GPU capacity on the mittwald AI infrastructure. Unlike shared hosting, your workloads run on hardware allocated solely to you.
+
+## What you get {#what-you-get}
+
+| Feature | Description |
+|---------|-------------|
+| **Exclusive GPU capacity** | Your models run on GPUs reserved only for you. |
+| **Your own API endpoint** | You receive a dedicated HTTPS endpoint on a customer subdomain under `llm.aihosting.mittwald.de`, e.g. `https://your-company.llm.aihosting.mittwald.de/v1`. |
+| **Dedicated API key** | Access is controlled by a dedicated API key tied to your endpoint. |
+| **OpenAI-compatible API** | Any application or library that supports OpenAI can connect. |
+| **EU-hosted, GDPR-compliant** | Compute and data remain in EU data centers operated by mittwald. |
+| **Predictable performance** | Your capacity is isolated from other customers. |
+
+## Current product scope {#current-scope}
+
+Dedicated AI Hosting is currently in its first release stage.
+
+### Model scope {#model-scope}
+
+Your available models are defined per customer contract and rollout stage. Model discovery and first-request flow are documented in [Getting started](./getting-started).
+
+### Capacity scope {#capacity-scope}
+
+Your dedicated capacity (for example, instance count and sizing) is provisioned according to your agreed scope.
+
+### Hardware profile (current offering) {#hardware-profile}
+
+Dedicated AI Hosting currently uses **NVIDIA RTX PRO 6000 Blackwell Server Edition** GPUs.
+
+Relevant specs for model planning:
+
+- **96 GB GDDR7 VRAM per GPU**
+- **1597 GB/s memory bandwidth**
+- **Up to 600 W configurable power**
+- **Native Blackwell Tensor Core support for low-precision inference (including FP4/NVFP4-class deployments)**
+
+These values are published by NVIDIA and help estimate whether a model fits on one GPU or needs multi-GPU placement.
+
+### Model sizing guidance (examples) {#model-sizing}
+
+Model fit depends on precision/quantization, context length, KV-cache settings, and concurrent load. As a practical planning rule:
+
+- **Usually fits on 1 GPU (96 GB):** many 7B-32B class models, and some larger quantized variants
+- **Often needs 2 GPUs:** many 70B-120B class deployments, especially with larger context windows
+- **Can stretch across several GPUs:** very large models or configurations with high context and throughput targets
+
+Example patterns (customer-specific, not fixed defaults):
+
+- Single-card style deployment: `Qwen3.6 8B` class, `Llama 3.3 8B` class
+- Two-card style deployment: `Qwen3.6 32B/35B` class, `Llama 3.3 70B` class
+
+Final sizing is validated during onboarding against your target latency and throughput.
+
+### Rough VRAM estimator (before contacting us) {#vram-estimator}
+
+You can do a quick pre-check with a simple calculator:
+
+1. **Weights memory**
+: `weights bytes ~= params count * bytes per weight`
+
+2. **KV cache per token**
+: `kv per token bytes ~= 2 * layer count * kv width * bytes per kv value`
+
+`kv width` is often close to hidden size for rough planning.
+
+3. **Total KV cache**
+: `total kv bytes ~= concurrent sequences * total tokens * kv per token bytes`
+
+`total tokens = input tokens + output tokens`
+
+4. **Total GPU target**
+: `total gpu bytes ~= weights bytes + total kv bytes + runtime overhead`
+
+Use a safety margin for runtime overhead (allocator fragmentation, CUDA buffers, runtime metadata). A practical planning range is **+15% to +30%**.
+
+#### Worked example from Hugging Face: Qwen3.6-35B-A3B {#vram-example}
+
+Model page: [Qwen/Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwen3.6-35B-A3B)
+
+How to read values from the model page:
+
+- From **Model size / Parameters**: ~`36B params`
+- From **Model Overview**: `40 layers`, hidden dimension `2048`
+- From **Tensor type**: `BF16` (2 bytes per weight value)
+- From **Context**: up to `262,144` tokens (long context increases KV cache strongly)
+
+Now estimate on **1x RTX PRO 6000 Blackwell (96 GB VRAM)**:
+
+1. Weights memory (BF16)
+: `36,000,000,000 * 2 ~= 72,000,000,000 bytes` (~72 GB decimal)
+
+2. KV cache per token (rough, using hidden size as kv width)
+: `2 * 40 * 2048 * 2 = 327,680 bytes per token` (~0.3125 MiB per token)
+
+3. Add safety headroom
+: with 20% overhead target, usable planning budget is about `96 GB / 1.2 ~= 80 GB`
+
+4. Budget left for KV cache
+: `80 GB - 72 GB ~= 8 GB` for KV cache
+
+5. Rough token capacity on one GPU at concurrency 1
+: `8 GB / 327,680 bytes ~= 24k-26k total tokens`
+
+This `total tokens` is input + output together.
+Example: `16k input + 8k output = 24k total`.
+
+If you use lower-precision KV cache (for compatible model/checkpoint stacks), this can improve token capacity significantly.
+
+#### Quantization options from Hugging Face model tree (non-GGUF) {#quantization-options}
+
+Source model tree: [Qwen3.6-35B-A3B quantizations](https://huggingface.co/models?other=base_model:quantized:Qwen/Qwen3.6-35B-A3B)
+
+For dedicated server deployments, practical non-GGUF families include:
+
+- **FP8 checkpoints** (example: [Qwen/Qwen3.6-35B-A3B-FP8](https://huggingface.co/Qwen/Qwen3.6-35B-A3B-FP8))
+- **NVFP4 checkpoints** (example: [RedHatAI/Qwen3.6-35B-A3B-NVFP4](https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4))
+- **AWQ INT4 checkpoints** (example families like `...-AWQ` in the same model tree)
+
+We intentionally exclude GGUF variants in this sizing path because this guide targets dedicated API serving stacks rather than local desktop runtimes.
+
+#### How quantization changes the same 1-GPU estimate {#quantization-estimate}
+
+Same assumptions as above:
+
+- 1x RTX PRO 6000 Blackwell (`96 GB`)
+- 20% safety margin -> planning budget ~`80 GB`
+- KV cache per token (BF16 KV) ~`327,680 bytes`
+- KV cache per token (FP8 KV) ~`163,840 bytes` (about half vs BF16 KV)
+
+Approximate weight memory by format:
+
+- **BF16**: `~72 GB` (36B * 2 bytes)
+- **FP8**: `~36 GB` (36B * 1 byte)
+- **4-bit family (NVFP4/AWQ)**: theoretical `~18 GB` (+metadata/scale overhead, so often higher in practice)
+
+Resulting rough total-token budget at concurrency 1 (input + output):
+
+- **BF16 weights + BF16 KV**: ~`24k-26k` tokens
+- **BF16 weights + FP8 KV**: ~`49k-52k` tokens (roughly 2x vs BF16 KV)
+- **FP8 weights + BF16 KV**: ~`130k+` tokens
+- **FP8 weights + FP8 KV**: ~`260k+` tokens (often near model context ceilings)
+- **4-bit weights + BF16 KV**: ~`170k+` tokens (practical real value may be lower due to overhead/runtime limits)
+- **4-bit weights + FP8 KV**: potentially much higher token budget, but usually constrained by model context limits and runtime behavior before raw VRAM is fully used
+
+This is only first-pass planning. Final usable limits depend on checkpoint packaging, KV-cache format support, multimodal memory use, and runtime behavior under concurrency.
+
+#### Quick rule-of-thumb {#quick-rules}
+
+- Longer context and higher concurrency increase KV cache linearly.
+- Quantization lowers weights memory a lot, but KV cache can still dominate at long context.
+- If the estimate is near VRAM limits, plan multi-GPU placement or lower context/concurrency.
+
+### Quantization and precision options {#precision-options}
+
+Depending on model and runtime, deployments can be planned with different numeric formats, for example:
+
+- `BF16` / `FP16` (quality-first, higher memory usage)
+- `FP8` (common performance/capacity tradeoff)
+- `NVFP4` / other low-bit variants (maximize fit and throughput for very large models)
+
+Which format is best depends on your quality requirements, latency target, and context window.
+Not every model is available in every quantization format, so compatibility is validated model-by-model.
+
+Practical KV-cache quantization guidance:
+
+- **FP8 KV cache can roughly double context capacity vs BF16 KV cache** in many setups.
+- This only works reliably when the selected checkpoint includes compatible KV-scale metadata/calibration.
+- If those scales are missing, runtimes may fall back to BF16 KV cache (higher VRAM use) or show quality/performance issues.
+- Some model stacks require BF16 KV cache for stable output quality; we validate this per model before production rollout.
+
+### Model classes seen in current market trends {#model-classes}
+
+Recent Hugging Face trending models span very different classes, including:
+
+- compact models around `7B-9B`
+- mid-size models around `27B-36B` (including MoE/A3B variants)
+- large models in `70B+` classes
+
+This is why dedicated sizing is always use-case specific.
+
+:::note[Sizing is always done together]
+Please plan model, precision, and capacity choices in a personal consultation with us. We validate fit, throughput, and cost before go-live.
+:::
+
+### Included platform features {#platform-features}
+
+- Dedicated endpoint and API key
+- Router-managed distribution across your provisioned capacity
+- Automatic failover within your dedicated setup
+
+### LiteLLM vs Bifrost (when to use what) {#litellm-vs-bifrost}
+
+Many customers do not use only one endpoint. If you route across multiple providers or additional self-hosted endpoints, use this split:
+
+| Goal | Recommended component |
+|------|------------------------|
+| Per-customer key issuance, key revoke/block, spend limits, usage by key | **LiteLLM** |
+| Multi-provider routing, fallback chains, weighted traffic split | **Bifrost** |
+| Both governance + routing across multiple endpoints | **LiteLLM + Bifrost together** |
+
+Typical patterns:
+
+- **Only your dedicated mittwald endpoint + customer key lifecycle**: LiteLLM alone is usually enough.
+- **Dedicated mittwald endpoint + other external/self-hosted model endpoints**: Bifrost is recommended for routing policy.
+- **Dedicated + shared + Anthropic/Claude (or other providers)**: Bifrost is the routing layer for model/provider-specific traffic decisions.
+- **Customer keys + multi-endpoint routing**: run LiteLLM in front of Bifrost.
+: request flow: `client -> LiteLLM -> Bifrost -> selected provider endpoint`
+
+### Not included in the initial scope {#not-included}
+
+- Grafana/metrics dashboards
+- Self-service provisioning via mStudio
+
+:::info Getting started
+Start with the [Getting started guide](./getting-started). If you want multi-key management and usage tracking, follow the [LiteLLM guide](./litellm).
+:::
+
+
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/10-getting-started.mdx b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/10-getting-started.mdx
new file mode 100644
index 00000000..9538ddb7
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/10-getting-started.mdx
@@ -0,0 +1,187 @@
+---
+sidebar_label: Erste Schritte
+description: So sendest du die erste Anfrage an deinen Dedicated-AI-Hosting-Endpunkt
+title: Erste Schritte mit Dedicated AI Hosting
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+Nach unserem Setup bekommst du:
+
+- **API Base URL** - deinen dedizierten HTTPS-Endpunkt, z. B. `https://dein-unternehmen.llm.aihosting.mittwald.de`
+- **API-Key** - ein Bearer-Token zur Authentifizierung deiner Requests
+
+Halte deinen API-Key vertraulich. Speichere ihn in einer Umgebungsvariablen oder einem Secrets-Manager — trage ihn nie direkt im Quellcode ein oder committe ihn in ein Repository. Falls ein Key kompromittiert wird, melde dich bei uns für eine Rotation.
+
+## Verfügbare Modelle prüfen {#list-models}
+
+```shellsession
+user@local $ curl https://dein-unternehmen.llm.aihosting.mittwald.de/v1/models \
+ -H "Authorization: Bearer YOUR_API_KEY"
+```
+
+Verwende eine der zurückgegebenen Modell-IDs als `YOUR_MODEL_ID`.
+
+:::note
+Wenn auf deinem Endpunkt noch kein Modell installiert wurde, kann diese Liste leer sein. In dem Fall melde dich bei uns, damit wir die Modell-Provisionierung abschließen.
+:::
+
+## Erste Anfrage senden {#first-request}
+
+
+
+
+```shellsession
+user@local $ curl https://dein-unternehmen.llm.aihosting.mittwald.de/v1/chat/completions \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "YOUR_MODEL_ID",
+ "messages": [
+ {"role": "user", "content": "Erkläre Retrieval-Augmented Generation in zwei Sätzen."}
+ ]
+ }'
+```
+
+
+
+
+```shellsession
+user@local $ pip install openai python-dotenv
+```
+
+```env
+OPENAI_API_KEY=YOUR_API_KEY
+OPENAI_BASE_URL=https://dein-unternehmen.llm.aihosting.mittwald.de/v1
+```
+
+```python
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI()
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[
+ {"role": "user", "content": "Erkläre Retrieval-Augmented Generation in zwei Sätzen."}
+ ]
+)
+
+print(response.choices[0].message.content)
+```
+
+
+
+
+```shellsession
+user@local $ npm install openai dotenv
+```
+
+```env
+OPENAI_API_KEY=YOUR_API_KEY
+OPENAI_BASE_URL=https://dein-unternehmen.llm.aihosting.mittwald.de/v1
+```
+
+```typescript
+import OpenAI from "openai";
+import "dotenv/config";
+
+const client = new OpenAI({
+ apiKey: process.env.OPENAI_API_KEY,
+ baseURL: process.env.OPENAI_BASE_URL,
+});
+
+const response = await client.chat.completions.create({
+ model: "YOUR_MODEL_ID",
+ messages: [
+ { role: "user", content: "Erkläre Retrieval-Augmented Generation in zwei Sätzen." }
+ ],
+});
+
+console.log(response.choices[0].message.content);
+```
+
+
+
+
+## Streaming-Antworten {#streaming}
+
+Mit `"stream": true` empfängst du Tokens direkt beim Generieren, anstatt auf die vollständige Antwort zu warten.
+
+
+
+
+```shellsession
+user@local $ curl https://dein-unternehmen.llm.aihosting.mittwald.de/v1/chat/completions \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "YOUR_MODEL_ID",
+ "stream": true,
+ "messages": [
+ {"role": "user", "content": "Erkläre Retrieval-Augmented Generation in zwei Sätzen."}
+ ]
+ }'
+```
+
+
+
+
+```python
+from openai import OpenAI
+
+client = OpenAI(api_key="YOUR_API_KEY", base_url="https://dein-unternehmen.llm.aihosting.mittwald.de/v1")
+
+with client.chat.completions.stream(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "Erkläre Retrieval-Augmented Generation in zwei Sätzen."}],
+) as stream:
+ for chunk in stream:
+ if chunk.choices[0].delta.content:
+ print(chunk.choices[0].delta.content, end="", flush=True)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "YOUR_API_KEY",
+ baseURL: "https://dein-unternehmen.llm.aihosting.mittwald.de/v1",
+});
+
+const stream = await client.chat.completions.create({
+ model: "YOUR_MODEL_ID",
+ stream: true,
+ messages: [{ role: "user", content: "Erkläre Retrieval-Augmented Generation in zwei Sätzen." }],
+});
+
+for await (const chunk of stream) {
+ process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
+}
+```
+
+
+
+
+:::note
+Wenn eine Streaming-Anfrage unterbrochen wird (z. B. durch einen Netzwerk-Timeout oder einen Server-Neustart), schließt sich die Verbindung, anstatt einen HTTP-Fehlercode zurückzugeben. Das HTTP 200 wird beim Start des Streams geschrieben – ein Fehler mitten im Stream sieht auf Client-Seite wie ein Connection-Reset aus. Erkenne unvollständige Streams und sende die Anfrage in diesem Fall erneut.
+:::
+
+## Request-Parameter {#parameters}
+
+Parameterempfehlungen können modellspezifisch sein. Starte mit den SDK-Defaults und tune dann gemäß Modellverhalten und Use Case.
+
+## Drop-in-Replacement {#drop-in}
+
+Da der Endpunkt OpenAI-kompatibel ist, kannst du ihn als Drop-in-Replacement in Frameworks mit eigener Base-URL nutzen. Eine vollständige Übersicht der unterstützten Endpunkte und Parameter — einschließlich Tool Calling und strukturierter Ausgaben — findest du unter [OpenAI-API-Kompatibilität](../openai-compatibility).
+
+## Mehrere API-Keys verwalten {#key-management}
+
+Wenn du getrennte Keys pro App/Team, Nutzungsstatistiken oder per-Key-Rate-Limits brauchst, nutze [LiteLLM](../litellm) als Self-Hosted-Proxy.
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/20-litellm.mdx b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/20-litellm.mdx
new file mode 100644
index 00000000..1de0a661
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/20-litellm.mdx
@@ -0,0 +1,304 @@
+---
+sidebar_label: Key-Management mit LiteLLM
+description: LiteLLM als Self-Hosted-Gateway für API-Key-Lifecycle, Budgets, Limits und Nutzungsanalyse
+title: End-to-end Key-Management mit LiteLLM
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+Dein Dedicated-Endpunkt enthält einen einzigen Upstream-API-Key. Mit LiteLLM machst du daraus eine vollständige Key-Management-Ebene: Keys pro App/Team/Kunde, Limits, Sperrung, Rotation und Nutzungsstatistiken.
+
+Das ist besonders relevant für deutsche Web- und Kreativagenturen mit vielen parallelen Kundenprojekten und klarer Mandantentrennung.
+
+## Was LiteLLM ergänzt {#what-it-adds}
+
+- Virtuelle Keys pro Anwendung, Team oder Endkunde
+- Limits pro Key (Requests/Minute, Tokens/Minute, Budget)
+- Key-Lifecycle-Steuerung (sperren, entsperren, rotieren, Ablaufzeit)
+- Nutzungs- und Kostenansicht pro Key, User und Team
+- Admin-UI plus API für Automatisierung
+
+## Voraussetzungen {#prerequisites}
+
+- Docker und Docker Compose
+- Dein Dedicated-Endpunkt und der Upstream-API-Key von mittwald
+- PostgreSQL (für persistentes Key-Management erforderlich)
+
+## A-bis-Z Setup {#setup}
+
+### 1. `.env` Datei anlegen {#setup-env}
+
+```env
+LITELLM_MASTER_KEY=sk-master-key-aendern
+UPSTREAM_BASE_URL=https://dein-unternehmen.llm.aihosting.mittwald.de
+UPSTREAM_API_KEY=YOUR_DEDICATED_API_KEY
+POSTGRES_USER=litellm
+POSTGRES_PASSWORD=db-passwort-aendern
+POSTGRES_DB=litellm
+UI_USERNAME=admin
+UI_PASSWORD=ui-passwort-aendern
+```
+
+### 2. `litellm_config.yaml` anlegen {#setup-config}
+
+```yaml
+model_list:
+ - model_name: YOUR_MODEL_ID
+ litellm_params:
+ model: openai/YOUR_MODEL_ID
+ api_base: os.environ/UPSTREAM_BASE_URL
+ api_key: os.environ/UPSTREAM_API_KEY
+
+general_settings:
+ master_key: os.environ/LITELLM_MASTER_KEY
+ database_url: os.environ/DATABASE_URL
+```
+
+### 3. `docker-compose.yml` anlegen {#setup-compose}
+
+```yaml
+services:
+ postgres:
+ image: postgres:16
+ environment:
+ POSTGRES_USER: ${POSTGRES_USER}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
+ POSTGRES_DB: ${POSTGRES_DB}
+ volumes:
+ - litellm-postgres:/var/lib/postgresql/data
+
+ litellm:
+ image: docker.litellm.ai/berriai/litellm:main-latest
+ depends_on:
+ - postgres
+ ports:
+ - "4000:4000"
+ environment:
+ LITELLM_MASTER_KEY: ${LITELLM_MASTER_KEY}
+ UPSTREAM_BASE_URL: ${UPSTREAM_BASE_URL}
+ UPSTREAM_API_KEY: ${UPSTREAM_API_KEY}
+ DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
+ volumes:
+ - ./litellm_config.yaml:/app/config.yaml
+ command: ["--config", "/app/config.yaml"]
+
+volumes:
+ litellm-postgres:
+```
+
+### 4. Services starten {#setup-start}
+
+```shellsession
+user@local $ docker compose up -d
+```
+
+### 5. Gateway + Modell-Passthrough prüfen {#setup-verify}
+
+```shellsession
+user@local $ curl http://localhost:4000/v1/models \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}"
+```
+
+Danach `http://localhost:4000/ui` öffnen und mit den `UI_USERNAME` / `UI_PASSWORD`-Werten aus der `.env`-Datei anmelden. Die Admin-UI startet automatisch zusammen mit dem Proxy — kein zusätzliches Flag notwendig.
+
+## Key-Lifecycle per API {#key-lifecycle}
+
+Die Endpunkte sind in den LiteLLM Virtual-Keys Docs und im Swagger dokumentiert.
+
+### Virtuellen Key erzeugen {#create-key}
+
+```shellsession
+user@local $ curl http://localhost:4000/key/generate \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "models": ["YOUR_MODEL_ID"],
+ "key_alias": "team-a-prod",
+ "metadata": {"owner": "team-a"},
+ "tpm_limit": 120000,
+ "rpm_limit": 300,
+ "max_budget": 250
+ }'
+```
+
+### Key-Infos, Limits und Nutzung abrufen {#key-info}
+
+```shellsession
+user@local $ curl "http://localhost:4000/key/info?key=sk-virtual-key" \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}"
+```
+
+In manchen Deployments gibt es zusätzlich versionierte Info-Routen (`/v2/key/info`).
+
+### Key sofort sperren {#key-block}
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/block \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"key":"sk-virtual-key"}'
+```
+
+### Key entsperren {#key-unblock}
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/unblock \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"key":"sk-virtual-key"}'
+```
+
+### Key rotieren {#key-rotate}
+
+Key-Rotation erfolgt durch Erstellen eines neuen Keys mit denselben Einstellungen und anschließendes Löschen des alten:
+
+```shellsession
+user@local $ curl http://localhost:4000/key/generate \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "models": ["YOUR_MODEL_ID"],
+ "key_alias": "team-a-prod-v2",
+ "metadata": {"owner": "team-a"}
+ }'
+```
+
+Anschließend den alten Key löschen:
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/delete \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"keys":["sk-alter-virtual-key"]}'
+```
+
+### Key dauerhaft entziehen {#key-revoke}
+
+```shellsession
+user@local $ curl -X POST http://localhost:4000/key/delete \
+ -H "Authorization: Bearer ${LITELLM_MASTER_KEY}" \
+ -H "Content-Type: application/json" \
+ -d '{"keys":["sk-virtual-key"]}'
+```
+
+## Admin-UI {#ui}
+
+Die Admin-UI ist unter `http://localhost:4000/ui` erreichbar. Anmelden mit den Zugangsdaten aus `UI_USERNAME` und `UI_PASSWORD` in deiner `.env`-Datei.
+
+Die Swagger-API-Referenz (alle Proxy-Endpunkte) ist unter `http://localhost:4000/` verfügbar.
+
+### Keys {#ui-keys}
+
+Der Bereich **Keys** zeigt alle virtuellen Keys mit aktuellem Verbrauch, Limits und Status.
+
+Verfügbare Aktionen:
+
+| Aktion | Was sie tut |
+|--------|-------------|
+| Key erstellen | Alias, Modell-Allowlist, TPM/RPM-Limits, Max-Budget, Ablaufdatum, Team-/User-Zuordnung setzen |
+| Key bearbeiten | Limits, Budget und Metadaten anpassen ohne den Key neu zu erstellen |
+| Key sperren | Zugriff sofort unterbinden — Anfragen mit diesem Key erhalten 401 |
+| Key entsperren | Zugriff wiederherstellen |
+| Key löschen | Dauerhaft entziehen — nicht rückgängig zu machen |
+
+### Verbrauchs- und Nutzungs-Dashboard {#ui-spend}
+
+Das Dashboard zeigt Verbrauch und Anfragevolumen aufgeschlüsselt nach:
+
+- **Pro Key** — wie viel jeder virtuelle Key verbraucht hat
+- **Pro User** — Verbrauch je User-ID, die Keys zugewiesen wurde
+- **Pro Team** — Gesamtverbrauch aller Keys eines Teams
+
+Verbrauchsresets sind per API (`POST /global/spend/reset`) für Admins möglich.
+
+### Teams {#ui-teams}
+
+Teams fassen Keys und User unter einem gemeinsamen Budget und einer Modell-Allowlist zusammen. Team erstellen, dann beim Key-Generieren zuweisen. Das Team-Dashboard zeigt aggregierten Verbrauch und Key-Aktivität.
+
+### User {#ui-users}
+
+Der Bereich **Users** zeigt alle User mit zugewiesenen Keys und ihrem Verbrauch. User können erstellt und Teams zugewiesen werden. User können optional eingeladen werden, sich selbst in der UI anzumelden und ihre eigenen Keys zu verwalten.
+
+### Modelle {#ui-models}
+
+Im Bereich **Models** können Modelle hinzugefügt oder angepasst werden, ohne den Proxy neu zu starten. Preisdaten lassen sich von GitHub synchronisieren, um Kostenberechnungen aktuell zu halten.
+
+## Nutzungsstatistiken und Kostensteuerung {#statistics}
+
+LiteLLM trackt Nutzung/Kosten auf Proxy-Requests und bietet:
+
+- Pro Key: Nutzung/Kosten (`/key/info`)
+- Pro User/Team: User- und Team-Info-Endpunkte
+- Dashboard-Ansichten für Traffic, Limits und Key-Aktivität
+
+## Dedicated-Kapazität an eigene Kunden weiterverkaufen {#reselling}
+
+Dieses Setup ist für Reseller-Szenarien geeignet. Deine Kunden nutzen dein AI-Produkt, während der Upstream-mittwald-Key privat bleibt.
+
+Empfohlenes Reseller-Muster:
+
+1. Upstream-Dedicated-Key nur in LiteLLM halten
+2. Pro Kunde/App/Umgebung einen virtuellen Key ausstellen
+3. Pro Key Limits und Budgets nach Tarif setzen
+4. Für den Lifecycle block/unblock/rotate/delete nutzen
+
+So bekommst du Mandantenkontrolle und Abrechnung auf Kundenniveau, ohne Upstream-Credentials offenzulegen.
+
+Für Agenturmodelle passt das sehr gut zu:
+
+- einem virtuellen Key pro Kundenprojekt
+- getrennten Kontingenten für Staging und Produktion
+- vertraglich abgestuften Limits je Kundentarif
+
+## Virtuelle Keys in Apps verwenden {#clients}
+
+
+
+
+```env
+OPENAI_BASE_URL=http://localhost:4000/v1
+OPENAI_API_KEY=sk-virtual-key
+```
+
+
+
+
+```python
+from openai import OpenAI
+
+client = OpenAI(api_key="sk-virtual-key", base_url="http://localhost:4000/v1")
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "Hallo"}],
+)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "sk-virtual-key",
+ baseURL: "http://localhost:4000/v1",
+});
+```
+
+
+
+
+## Betriebliche Empfehlungen {#ops}
+
+- LiteLLM und Datenbank persistent betreiben (kein In-Memory-only Setup in Produktion)
+- Starken `master_key` verwenden und regelmäßig rotieren
+- Admin-Oberfläche nur kontrolliert exponieren
+- Key-Richtlinien vor Kunden-Rollout mit Testkeys validieren
+
+## Referenzen {#references}
+
+- [LiteLLM Virtual Keys](https://docs.litellm.ai/docs/proxy/virtual_keys)
+- [LiteLLM Admin UI](https://docs.litellm.ai/docs/proxy/ui)
+- [LiteLLM Swagger / Endpoints](https://www.litellm.org/)
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/30-bifrost.mdx b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/30-bifrost.mdx
new file mode 100644
index 00000000..b1056edd
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/30-bifrost.mdx
@@ -0,0 +1,290 @@
+---
+sidebar_label: AI-Gateway mit Bifrost
+description: Bifrost als Self-Hosted-Gateway vor deinem Dedicated-Endpunkt betreiben
+title: End-to-end Gateway-Setup mit Bifrost
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+Bifrost ist ein AI-Gateway für Routing, Failover und Provider-Governance. In einem Dedicated-Setup sitzt Bifrost zwischen deinen Anwendungen und deinem mittwald Endpunkt.
+
+Für Web- und Kreativagenturen hilft Bifrost dabei, Routing über viele Kundenworkloads, Kampagnenspitzen und gemischte Provider-Landschaften zentral zu steuern.
+
+## Wann Bifrost statt LiteLLM {#when-to-use}
+
+- **LiteLLM** für virtuellen Endkunden-Key-Lifecycle, Budgets und Kostenansicht
+- **Bifrost** für Provider-Routing, Fallback-Ketten und Gateway-Richtlinien
+- Häufig kombiniert: LiteLLM für Kundenschlüssel, Bifrost für Upstream-Routing
+
+## Voraussetzungen {#prerequisites}
+
+- Docker installiert
+- Dedicated-Endpunkt-URL und API-Key von mittwald
+
+## A-bis-Z Setup {#setup}
+
+### 1. Bifrost starten {#setup-start}
+
+```shellsession
+user@local $ docker run -d \
+ --name bifrost \
+ -p 8080:8080 \
+ -v "$(pwd)/data:/app/data" \
+ maximhq/bifrost
+```
+
+`http://localhost:8080` öffnen.
+
+### 2. Dedicated-Endpunkt als OpenAI-kompatiblen Provider registrieren {#setup-register}
+
+Provider-Registrierung und Key-Registrierung sind zwei separate API-Aufrufe.
+
+**Schritt 1 — Provider registrieren** (setzt Base URL und Netzwerkkonfiguration):
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "provider": "openai",
+ "network_config": {
+ "base_url": "https://dein-unternehmen.llm.aihosting.mittwald.de/v1"
+ }
+ }'
+```
+
+**Schritt 2 — API-Key zum Provider hinzufügen**:
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers/openai/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "name": "mittwald-dedicated",
+ "value": "YOUR_DEDICATED_API_KEY",
+ "models": ["*"],
+ "weight": 1.0
+ }'
+```
+
+### 3. Provider-Konfiguration in der UI prüfen {#setup-validate}
+
+Unter **Model Providers** prüfen:
+
+- Key aktiv
+- Modell-Mapping korrekt (`*` oder explizite Liste)
+- Base URL zeigt auf deinen Dedicated-Endpunkt
+
+### 4. Traffic über Bifrost senden {#setup-traffic}
+
+
+
+
+```shellsession
+user@local $ curl http://localhost:8080/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "openai/YOUR_MODEL_ID",
+ "messages": [
+ {"role": "user", "content": "Hallo"}
+ ]
+ }'
+```
+
+
+
+
+```python
+from openai import OpenAI
+
+client = OpenAI(api_key="dummy", base_url="http://localhost:8080/openai/v1")
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "Hallo"}],
+)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "dummy",
+ baseURL: "http://localhost:8080/openai/v1",
+});
+```
+
+
+
+
+## Routing zu mittwald Shared AI Hosting (zusätzlich zu Dedicated) {#shared-routing}
+
+Wenn du zusätzlich mittwald Shared AI Hosting nutzt, kannst du es als weiteren OpenAI-kompatiblen Provider anbinden.
+
+Shared-AI-Hosting Base URL:
+
+- `https://llm.aihosting.mittwald.de/v1`
+
+Beispiel — Provider registrieren und Key hinzufügen:
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "provider": "mittwald-shared",
+ "network_config": {
+ "base_url": "https://llm.aihosting.mittwald.de/v1"
+ },
+ "custom_provider_config": {
+ "base_provider_type": "openai"
+ }
+ }'
+
+curl --location 'http://localhost:8080/api/providers/mittwald-shared/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "name": "mittwald-shared-key",
+ "value": "YOUR_SHARED_API_KEY",
+ "models": ["*"],
+ "weight": 1.0
+ }'
+```
+
+## Routing-Regeln: wann Dedicated vs Shared {#routing-rules}
+
+Routing-Entscheidungen in Bifrost basieren typischerweise auf:
+
+- Modell-zu-Key-Mapping (`models` pro Key)
+- Gewichtung (`weight`)
+- Fallback-Reihenfolge (primärer Provider, sekundärer Provider)
+
+Empfohlene Regeln:
+
+1. Premium/vertragliche Workloads -> Dedicated-Provider-Key
+2. Burst- oder Long-Tail-Workloads -> Shared-Provider-Key
+3. Fallback-Pfad -> Dedicated zuerst, Shared danach (oder umgekehrt, je nach SLO-/Kostenziel)
+
+Beispiel für modellspezifische Aufteilung:
+
+- Key `dedicated-key`: `models: ["YOUR_PREMIUM_MODEL_ID"]`
+- Key `shared-key`: `models: ["*"]` (oder explizite Nicht-Premium-Liste)
+
+So bleibt hochwertiger Traffic auf reservierter Kapazität, während Shared Hosting für zusätzliche Skalierung genutzt werden kann.
+
+Du kannst zusätzlich weitere Provider (z. B. Anthropic / Claude) anbinden und bestimmte Workloads gezielt dorthin routen.
+
+Beispiel für einen zusätzlichen Provider:
+
+```shellsession
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{"provider": "anthropic"}'
+
+user@local $ curl --location 'http://localhost:8080/api/providers/anthropic/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "name": "claude-key",
+ "value": "YOUR_ANTHROPIC_API_KEY",
+ "models": ["claude-3-7-sonnet", "claude-4-sonnet"],
+ "weight": 1.0
+ }'
+```
+
+## Agentur-orientierte Routing-Szenarien {#agency-scenarios}
+
+Typische Agenturrealität in Deutschland:
+
+- viele Kundenwebsites/-apps
+- gemischte Workloads (Chatbot, Content-Generierung, Backoffice-Automation)
+- schwankende Lasten (Kampagnenstarts, saisonale Peaks)
+
+Empfohlene Richtlinien:
+
+- Premium-Kundenworkloads auf Dedicated-Kapazität halten
+- unkritischen oder Burst-Traffic auf Shared-Kapazität legen
+- bestimmte Aufgaben (z. B. Copywriting/Review-Workflows) gezielt zu Claude routen
+- immer eine Fallback-Route für Ausfallsicherheit aktiv halten
+
+So können Agenturen stabile SLAs für Kernkunden anbieten und gleichzeitig Betriebskosten kontrollieren.
+
+## Vollständiges Multi-Lane-Routing-Beispiel {#full-example}
+
+Dieses Beispiel richtet in einer Sequenz drei Lanes ein: dedizierte mittwald-Kapazität als primäre Lane, Shared mittwald-Kapazität als Burst-/Fallback-Lane und Anthropic als separate Lane für bestimmte Aufgaben. Die drei Provider-Registrierungen lassen sich direkt kopieren und anpassen; das Routing erfolgt über den Modellnamen.
+
+```shellsession
+# Lane 1: dedizierter mittwald-Endpunkt (primär, reservierte Kapazität)
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{"provider": "openai", "network_config": {"base_url": "https://dein-unternehmen.llm.aihosting.mittwald.de/v1"}}'
+
+user@local $ curl --location 'http://localhost:8080/api/providers/openai/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{"name": "mittwald-dedicated", "value": "YOUR_DEDICATED_API_KEY", "models": ["YOUR_PREMIUM_MODEL_ID"], "weight": 1.0}'
+
+# Lane 2: Shared mittwald-Endpunkt (Burst- und Long-Tail-Workloads)
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{"provider": "mittwald-shared", "network_config": {"base_url": "https://llm.aihosting.mittwald.de/v1"}, "custom_provider_config": {"base_provider_type": "openai"}}'
+
+user@local $ curl --location 'http://localhost:8080/api/providers/mittwald-shared/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{"name": "mittwald-shared-key", "value": "YOUR_SHARED_API_KEY", "models": ["*"], "weight": 1.0}'
+
+# Lane 3: Anthropic (für bestimmte Aufgabentypen, Routing über Modellnamen)
+user@local $ curl --location 'http://localhost:8080/api/providers' \
+ --header 'Content-Type: application/json' \
+ --data '{"provider": "anthropic"}'
+
+user@local $ curl --location 'http://localhost:8080/api/providers/anthropic/keys' \
+ --header 'Content-Type: application/json' \
+ --data '{"name": "claude-key", "value": "YOUR_ANTHROPIC_API_KEY", "models": ["claude-3-7-sonnet", "claude-4-sonnet"], "weight": 1.0}'
+```
+
+Nach der Registrierung wird der Request über den Modellnamen an die richtige Lane geleitet:
+
+- `YOUR_PREMIUM_MODEL_ID` → trifft die Dedicated-Lane
+- Jedes Modell, das auf `*` im Shared-Provider passt → trifft die Shared-Lane
+- `claude-3-7-sonnet` oder `claude-4-sonnet` → trifft die Anthropic-Lane
+
+Fallback-Verhalten (Dedicated → Shared) greift automatisch, wenn der primäre Provider-Key nicht erreichbar ist. Mit dem `weight`-Parameter lässt sich die Lastverteilung steuern.
+
+## Produktionsmuster {#production-patterns}
+
+### Provider-Failover und Lastverteilung {#production-failover}
+
+- Mehrere Keys/Provider hinzufügen
+- Über `weight` den Traffic verteilen
+- Modellspezifische Schlüssel für Premium-/Standard-Lanes
+
+### Härtung für Self-Hosted-Endpunkte {#production-hardening}
+
+- Wenn möglich explizite Modell-Allowlists statt `*`
+- Timeouts in `network_config` setzen
+- In Kubernetes bei Namespace-übergreifenden Zielen FQDNs nutzen
+
+### Logging und Observability {#production-logging}
+
+Provider-seitige Raw-Request/Response-Logs nur aktivieren, wenn für Compliance wirklich nötig.
+
+## Kombination mit LiteLLM (für Kunden-Keys empfohlen) {#combination}
+
+Robustes Muster:
+
+1. Kunden-Apps -> LiteLLM virtuelle Keys
+2. LiteLLM Upstream -> Bifrost
+3. Bifrost -> Dedicated-Endpunkt
+
+Ergebnis:
+
+- Sauberer Kunden-Key-Lifecycle und Kostenkontrolle
+- Gateway-Routing/Fallback auf Upstream-Ebene
+- Klare Trennung der Verantwortlichkeiten
+
+## Referenzen {#references}
+
+- [Bifrost Setting Up](https://docs.getbifrost.ai/quickstart/gateway/setting-up)
+- [Bifrost Provider Configuration](https://docs.getbifrost.ai/quickstart/gateway/provider-configuration)
+- [Bifrost OpenAI SDK Integration](https://docs.getbifrost.ai/integrations/openai-sdk/overview)
+- [LiteLLM Key-Management-Guide](../litellm)
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/40-error-handling.mdx b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/40-error-handling.mdx
new file mode 100644
index 00000000..7ae29912
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/40-error-handling.mdx
@@ -0,0 +1,108 @@
+---
+sidebar_label: Fehlerbehandlung und Retries
+description: HTTP-Fehlercodes, Retry-Empfehlungen und Kapazitätsverhalten für den Dedicated-AI-Hosting-Endpunkt
+title: Fehlerbehandlung und Retries
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+Diese Seite beschreibt die HTTP-Fehlercodes, die deine Anwendung erhalten kann, das Kapazitätsverhalten des Endpunkts und wie du Retries korrekt konfigurierst.
+
+## HTTP-Fehlercodes {#error-codes}
+
+| Code | Bedeutung | Was tun |
+|------|-----------|---------|
+| `400` | Fehlerhafte Anfrage — Eingabe zu lang oder falsches Format | Eingabelänge reduzieren oder Anfrage korrigieren (siehe Kontextlimit unten) |
+| `401` | Ungültiger oder fehlender API-Key | `Authorization: Bearer YOUR_API_KEY` Header prüfen |
+| `503` | Service vorübergehend nicht verfügbar — Endpunkt überlastet oder neugestartet | Mit exponentiellem Backoff wiederholen |
+| `500` | Interner Serverfehler | Mit Backoff wiederholen; bei dauerhaftem Auftreten Support kontaktieren |
+| `502` | Bad Gateway | Mit Backoff wiederholen |
+| `504` | Gateway-Timeout — Anfrage hat zu lange gedauert | Eingabe verkleinern, Concurrency reduzieren oder wiederholen |
+
+:::note 401-Response-Format
+Der `401`-Response-Body lautet `{"error": "Unauthorized"}`. Das ist einfacher als das Standard-OpenAI-Fehlerformat und enthält keine Felder `type`, `param` oder `code`. Entsprechend in der Fehlerbehandlung berücksichtigen.
+:::
+
+## Kontextlimit {#context-limit}
+
+Anfragen, deren Gesamtanzahl an Tokens (Prompt + Completion) das konfigurierte Kontextfenster des Modells überschreitet, werden mit `400` abgewiesen. Die Antwort verwendet das OpenAI-Fehlerformat:
+
+```json
+{
+ "object": "error",
+ "message": "This model's maximum context length is X tokens. However, you requested Y tokens ...",
+ "type": "invalid_request_error",
+ "param": "messages",
+ "code": 400
+}
+```
+
+Das Kontextfenster des bereitgestellten Modells lässt sich im [Getting-started-Guide](../getting-started) über den `/v1/models`-Endpunkt abrufen. Plane Input + erwarteten Output so, dass sie innerhalb dieses Limits bleiben.
+
+## Maximale Request-Body-Größe {#body-size}
+
+Die maximale Request-Body-Größe beträgt **25 MB**. Anfragen darüber werden abgewiesen, bevor sie das Modell erreichen. Dieses Limit ist nur bei multimodalen Eingaben relevant (z. B. base64-kodierte Bilder). Standard-Text-Chat-Anfragen liegen weit darunter.
+
+## Verhalten unter hoher Last {#capacity}
+
+Der Endpunkt stellt Anfragen intern in eine Warteschlange, wenn alle Compute-Slots belegt sind. Das bedeutet:
+
+- Anfragen schlagen nicht sofort fehl, wenn das Modell beschäftigt ist — sie warten in der Queue.
+- Bei sehr hoher anhaltender Last können einige Anfragen schließlich ablaufen. Die Verbindung schließt sich dann als Connection-Reset, nicht als HTTP-Fehlercode. Das fällt besonders bei Streaming-Antworten auf (siehe [Streaming-Fehler](#streaming-failures) unten).
+- Der Endpunkt gibt `503` zurück, wenn er gar keine neuen Anfragen annehmen kann — zum Beispiel beim Neustart oder bei einem echten Serverfehler.
+
+Falls du unter deiner erwarteten Last regelmäßig hohe Latenz oder Timeouts erlebst, melde dich bei uns zur Überprüfung der bereitgestellten Kapazität.
+
+## Retry-Empfehlungen {#retries}
+
+Wiederhole Anfragen bei `503`, `502`, `500`. Bei `400` oder `401` nicht wiederholen.
+
+Empfohlenes Retry-Muster:
+
+1. Bei `5xx`: warten, dann erneut senden
+2. Starte mit **1 Sekunde Wartezeit**
+3. Verdopple die Wartezeit bei jedem weiteren Versuch (exponentieller Backoff)
+4. Begrenze die Wartezeit auf **60 Sekunden**
+5. Stoppe nach **5 Versuchen**
+
+Die meisten OpenAI-kompatiblen Client-Libraries haben eingebaute Retry-Logik, die direkt konfiguriert werden kann:
+
+
+
+
+```python
+import openai
+
+client = openai.OpenAI(
+ api_key="YOUR_API_KEY",
+ base_url="https://dein-unternehmen.llm.aihosting.mittwald.de/v1",
+ max_retries=5,
+)
+```
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "YOUR_API_KEY",
+ baseURL: "https://dein-unternehmen.llm.aihosting.mittwald.de/v1",
+ maxRetries: 5,
+});
+```
+
+
+
+
+## Streaming-Fehler {#streaming-failures}
+
+Bei Streaming-Anfragen (`"stream": true`) wird der HTTP-`200`-Response-Header geschrieben, sobald das erste Token bereit ist. Tritt danach ein Fehler auf (z. B. Timeout oder Server-Neustart), schließt sich die Verbindung als Connection-Reset — ohne HTTP-Fehlercode.
+
+Erkenne das, indem du prüfst, ob der Stream mit dem erwarteten Stop-Reason beendet wurde. Im Fehlerfall die Anfrage vollständig neu senden.
+
+## Unterstützte Protokolle {#protocol}
+
+Der Endpunkt unterstützt ausschließlich **HTTPS**. gRPC ist nicht verfügbar.
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/50-openai-compatibility.mdx b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/50-openai-compatibility.mdx
new file mode 100644
index 00000000..0e0a3125
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/50-openai-compatibility.mdx
@@ -0,0 +1,186 @@
+---
+sidebar_label: OpenAI-Kompatibilität
+description: Welche OpenAI-API-Endpunkte und Parameter auf dem Dedicated-AI-Hosting-Endpunkt unterstützt werden
+title: OpenAI-API-Kompatibilität
+---
+
+import Tabs from "@theme/Tabs";
+import TabItem from "@theme/TabItem";
+
+Der Dedicated-AI-Hosting-Endpunkt ist OpenAI-kompatibel. Jedes OpenAI-SDK oder jede Library lässt sich durch Änderung von zwei Werten umzeigen — die Base URL und der API-Key. Diese Seite dokumentiert genau, was unterstützt wird, was nicht, und wo das Verhalten vom gehosteten OpenAI-Dienst abweicht.
+
+## Wechsel von OpenAI {#migration}
+
+```python
+# Vorher
+client = OpenAI(api_key="sk-...")
+
+# Nachher
+client = OpenAI(
+ api_key="YOUR_DEDICATED_API_KEY",
+ base_url="https://dein-unternehmen.llm.aihosting.mittwald.de/v1",
+)
+```
+
+Der Modellname ändert sich ebenfalls. Verwende die ID aus `/v1/models` statt eines OpenAI-Modellnamens wie `gpt-4o`.
+
+## Unterstützte Endpunkte {#endpoints}
+
+| Endpunkt | Unterstützt |
+|----------|-------------|
+| `GET /v1/models` | ✅ |
+| `POST /v1/chat/completions` | ✅ |
+| `POST /v1/completions` | ✅ (Legacy-Text-Completions) |
+| `POST /v1/responses` | ✅ |
+| `POST /v1/embeddings` | ❌ — dieser Endpunkt betreibt ein generatives Modell, kein Embedding-Modell |
+| Assistants API (`/v1/assistants`, `/v1/threads`, …) | ❌ |
+| Batch API (`/v1/batches`) | ❌ |
+| Fine-tuning API (`/v1/fine_tuning`) | ❌ |
+| Files API (`/v1/files`) | ❌ |
+| Moderations API (`/v1/moderations`) | ❌ |
+| Audio-/Bild-Endpunkte | ❌ |
+
+## Parameter-Unterstützung für /v1/chat/completions {#parameters}
+
+| Parameter | Support | Hinweise |
+|-----------|---------|----------|
+| `model` | ✅ | Modell-ID aus `/v1/models` verwenden |
+| `messages` | ✅ | |
+| `stream` | ✅ | Siehe [Streaming](../getting-started#streaming) |
+| `temperature`, `top_p` | ✅ | |
+| `max_tokens` / `max_completion_tokens` | ✅ | |
+| `stop` | ✅ | |
+| `n` | ✅ | Mehrere Completions pro Anfrage |
+| `presence_penalty`, `frequency_penalty` | ✅ | |
+| `logprobs`, `top_logprobs` | ✅ | |
+| `tools`, `tool_choice` | ✅ | Siehe [Tool Calling](#tool-calling) |
+| `parallel_tool_calls` | ✅ | `false` begrenzt auf einen Tool-Call; `true` (Standard) erlaubt mehrere |
+| `response_format` | ✅ | Siehe [Strukturierte Ausgaben](#structured-outputs) |
+| `seed` | ⚠️ | Wird akzeptiert und weitergeleitet — Reproduzierbarkeit ist Best-Effort aufgrund von GPU-Nicht-Determinismus |
+| `user` | ⚠️ | Wird akzeptiert, aber ignoriert |
+| `logit_bias` | ✅ | Unterstützt; Token-IDs außerhalb des Modell-Vokabulars geben einen Validierungsfehler zurück |
+| `stream_options` | ✅ | Unterstützt bei `stream: true`; ohne Streaming gibt es einen Validierungsfehler. `include_usage: true` hängt am Ende des Streams einen Usage-Chunk an |
+
+## Strukturierte Ausgaben {#structured-outputs}
+
+Sowohl JSON-Object-Modus als auch JSON-Schema-Modus werden unterstützt.
+
+**JSON-Object-Modus** — beschränkt die Ausgabe auf valides JSON:
+
+```json
+{
+ "model": "YOUR_MODEL_ID",
+ "messages": [{"role": "user", "content": "Gib ein JSON-Objekt mit den Feldern name und age zurück."}],
+ "response_format": {"type": "json_object"}
+}
+```
+
+**JSON-Schema-Modus** — beschränkt die Ausgabe auf ein bestimmtes Schema:
+
+```json
+{
+ "model": "YOUR_MODEL_ID",
+ "messages": [{"role": "user", "content": "Extrahiere Name und Alter der Person."}],
+ "response_format": {
+ "type": "json_schema",
+ "json_schema": {
+ "name": "person",
+ "strict": true,
+ "schema": {
+ "type": "object",
+ "properties": {
+ "name": {"type": "string"},
+ "age": {"type": "integer"}
+ },
+ "required": ["name", "age"],
+ "additionalProperties": false
+ }
+ }
+ }
+}
+```
+
+:::note
+Der JSON-Schema-Modus verwendet Guided Decoding. Komplexe rekursive Schemata oder sehr große Schemata können die Latenz erhöhen.
+:::
+
+## Tool Calling {#tool-calling}
+
+Tool Calling (Function Calling) folgt dem OpenAI-Format. Übergib deine Tools im `tools`-Array und steuere das Verhalten über `tool_choice`.
+
+```python
+from openai import OpenAI
+
+client = OpenAI(
+ api_key="YOUR_API_KEY",
+ base_url="https://dein-unternehmen.llm.aihosting.mittwald.de/v1",
+)
+
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "Gibt das aktuelle Wetter für einen Ort zurück.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "Stadt und Land"},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+]
+
+response = client.chat.completions.create(
+ model="YOUR_MODEL_ID",
+ messages=[{"role": "user", "content": "Wie ist das Wetter in Berlin?"}],
+ tools=tools,
+ tool_choice="auto",
+)
+
+tool_calls = response.choices[0].message.tool_calls
+```
+
+`parallel_tool_calls=False` begrenzt das Modell auf maximal einen Tool-Call pro Turn, was die Verarbeitung in mehrstufigen Agent-Loops vereinfacht.
+
+## Client-Timeouts konfigurieren {#timeouts}
+
+LLM-Anfragen mit langen Eingaben oder Ausgaben können 60 Sekunden oder mehr dauern. Viele HTTP-Clients und Frameworks haben deutlich kürzere Standard-Timeouts. Setze deinen Client-Timeout explizit, um fehlerhafte Abbrüche zu vermeiden.
+
+
+
+
+```python
+import httpx
+from openai import OpenAI
+
+client = OpenAI(
+ api_key="YOUR_API_KEY",
+ base_url="https://dein-unternehmen.llm.aihosting.mittwald.de/v1",
+ timeout=httpx.Timeout(300.0, connect=10.0),
+)
+```
+
+Ein Read-Timeout von 300 Sekunden (5 Minuten) deckt die meisten Inference-Workloads ab. Bei sehr langen Kontexten oder hoher Parallelität ggf. erhöhen.
+
+
+
+
+```typescript
+import OpenAI from "openai";
+
+const client = new OpenAI({
+ apiKey: "YOUR_API_KEY",
+ baseURL: "https://dein-unternehmen.llm.aihosting.mittwald.de/v1",
+ timeout: 300 * 1000, // 300 Sekunden in Millisekunden
+});
+```
+
+
+
+
+:::note
+Der serverseitige Connection-Timeout beträgt 30 Minuten. Ein Client-Timeout, der kürzer ist als deine längste erwartete Anfrage, führt zu einem Client-seitigen Fehler, bevor der Server die Verbindung trennt.
+:::
diff --git a/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/index.mdx b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/index.mdx
new file mode 100644
index 00000000..393e08d6
--- /dev/null
+++ b/i18n/de/docusaurus-plugin-content-docs/current/platform/aihosting/70-dedicated/index.mdx
@@ -0,0 +1,226 @@
+---
+sidebar_label: Übersicht
+description: Dedicated AI Hosting - exklusive GPU-Kapazität für anspruchsvolle KI-Workloads
+title: Dedicated AI Hosting
+---
+
+import DocCardList from "@theme/DocCardList";
+
+Dedicated AI Hosting bietet dir exklusiven Zugriff auf reservierte GPU-Kapazität innerhalb der mittwald AI-Infrastruktur. Im Unterschied zum Shared Hosting laufen deine Workloads auf Hardware, die nur für dich bereitsteht.
+
+## Was du bekommst {#what-you-get}
+
+| Feature | Beschreibung |
+|---------|--------------|
+| **Exklusive GPU-Kapazität** | Deine Modelle laufen auf GPUs, die nur für dich reserviert sind. |
+| **Eigener API-Endpunkt** | Du erhältst einen dedizierten HTTPS-Endpunkt auf einer Kundensubdomain unter `llm.aihosting.mittwald.de`, z. B. `https://dein-unternehmen.llm.aihosting.mittwald.de/v1`. |
+| **Dedizierter API-Key** | Der Zugriff wird über einen dedizierten API-Key abgesichert. |
+| **OpenAI-kompatible API** | Anwendungen und Libraries mit OpenAI-Unterstützung funktionieren ohne Anpassung. |
+| **EU-Hosting, DSGVO-konform** | Compute und Daten bleiben in EU-Rechenzentren von mittwald. |
+| **Planbare Performance** | Deine Kapazität ist von anderen Kunden isoliert. |
+
+## Aktueller Produktumfang {#current-scope}
+
+Dedicated AI Hosting befindet sich aktuell im ersten Release-Umfang.
+
+### Modellumfang {#model-scope}
+
+Welche Modelle bei dir verfügbar sind, ist kundenspezifisch und hängt vom Rollout-Stand ab. Modellfindung und First-Request-Ablauf sind im [Getting-started-Guide](./getting-started) beschrieben.
+
+### Kapazitätsumfang {#capacity-scope}
+
+Deine dedizierte Kapazität (z. B. Anzahl und Sizing der Instanzen) wird gemäß vereinbartem Leistungsumfang bereitgestellt.
+
+### Hardware-Profil (aktuelles Angebot) {#hardware-profile}
+
+Dedicated AI Hosting nutzt aktuell **NVIDIA RTX PRO 6000 Blackwell Server Edition** GPUs.
+
+Relevante Eckdaten für die Modellplanung:
+
+- **96 GB GDDR7 VRAM pro GPU**
+- **1597 GB/s Speicherbandbreite**
+- **Bis zu 600 W konfigurierbare Leistungsaufnahme**
+- **Native Blackwell Tensor-Core-Unterstützung für Low-Precision-Inferenz (inklusive FP4/NVFP4-naher Deployments)**
+
+Diese Werte sind von NVIDIA veröffentlicht und helfen bei der Einschätzung, ob ein Modell auf einer GPU läuft oder über mehrere GPUs verteilt werden sollte.
+
+### Modell-Sizing (Beispiele) {#model-sizing}
+
+Ob ein Modell passt, hängt u. a. von Präzision/Quantisierung, Kontextlänge, KV-Cache-Einstellungen und Parallelität ab. Als praxisnahe Orientierung:
+
+- **Typisch auf 1 GPU (96 GB):** viele Modelle im Bereich 7B-32B, teils auch größere quantisierte Varianten
+- **Häufig auf 2 GPUs:** viele Deployments im Bereich 70B-120B, besonders bei größeren Kontextfenstern
+- **Auf mehrere GPUs streckbar:** sehr große Modelle oder Konfigurationen mit hohen Kontext- und Durchsatzanforderungen
+
+Beispielmuster (kundenspezifisch, keine festen Defaults):
+
+- Single-Card-Deployment: `Qwen3.6 8B` Klasse, `Llama 3.3 8B` Klasse
+- Two-Card-Deployment: `Qwen3.6 32B/35B` Klasse, `Llama 3.3 70B` Klasse
+
+Die finale Auslegung wird im Onboarding auf deine Ziel-Latenz und deinen Ziel-Durchsatz abgestimmt.
+
+### Grober VRAM-Rechner (vor dem Gespräch mit uns) {#vram-estimator}
+
+Für eine erste Einschätzung kannst du diese einfache Rechnung nutzen:
+
+1. **Gewichtsspeicher**
+: `weights bytes ~= params count * bytes per weight`
+
+2. **KV-Cache pro Token**
+: `kv per token bytes ~= 2 * layer count * kv width * bytes per kv value`
+
+`kv width` liegt für grobe Planung oft nahe an der hidden size.
+
+3. **Gesamter KV-Cache**
+: `total kv bytes ~= concurrent sequences * total tokens * kv per token bytes`
+
+`total tokens = input tokens + output tokens`
+
+4. **Zielwert für GPU-Speicher**
+: `total gpu bytes ~= weights bytes + total kv bytes + runtime overhead`
+
+Plane eine Sicherheitsreserve für Runtime-Overhead ein (Allocator-Fragmentierung, CUDA-Buffer, Runtime-Metadaten). Praxisnah sind **+15% bis +30%**.
+
+#### Rechenbeispiel von Hugging Face: Qwen3.6-35B-A3B {#vram-example}
+
+Modellseite: [Qwen/Qwen3.6-35B-A3B](https://huggingface.co/Qwen/Qwen3.6-35B-A3B)
+
+So liest du die Werte auf der Modellseite:
+
+- Aus **Model size / Parameters**: ca. `36B params`
+- Aus **Model Overview**: `40 layers`, hidden dimension `2048`
+- Aus **Tensor type**: `BF16` (2 Bytes pro Gewichts-Wert)
+- Aus **Context**: bis `262.144` Tokens (langer Kontext vergrößert KV-Cache stark)
+
+Beispielrechnung auf **1x RTX PRO 6000 Blackwell (96 GB VRAM)**:
+
+1. Gewichtsspeicher (BF16)
+: `36.000.000.000 * 2 ~= 72.000.000.000 bytes` (~72 GB dezimal)
+
+2. KV-Cache pro Token (grob, hidden size als kv width)
+: `2 * 40 * 2048 * 2 = 327.680 bytes pro Token` (~0,3125 MiB pro Token)
+
+3. Sicherheitsreserve
+: bei 20% Overhead liegt das nutzbare Planungsbudget bei etwa `96 GB / 1,2 ~= 80 GB`
+
+4. Verbleibend für KV-Cache
+: `80 GB - 72 GB ~= 8 GB` für KV-Cache
+
+5. Grobe Tokenkapazität auf einer GPU bei Concurrency 1
+: `8 GB / 327.680 bytes ~= 24k-26k Gesamt-Tokens`
+
+Diese `Gesamt-Tokens` sind Input + Output zusammen.
+Beispiel: `16k Input + 8k Output = 24k Gesamt`.
+
+Bei niedrigerer KV-Präzision (bei kompatiblem Modell/Checkpoint-Stack) steigt die Tokenkapazität deutlich.
+
+#### Quantisierungsoptionen aus dem Hugging-Face-Model-Tree (ohne GGUF) {#quantization-options}
+
+Quelle Model-Tree: [Qwen3.6-35B-A3B Quantizations](https://huggingface.co/models?other=base_model:quantized:Qwen/Qwen3.6-35B-A3B)
+
+Für dedizierte Server-Deployments sind praktisch vor allem diese Non-GGUF-Familien relevant:
+
+- **FP8-Checkpoints** (Beispiel: [Qwen/Qwen3.6-35B-A3B-FP8](https://huggingface.co/Qwen/Qwen3.6-35B-A3B-FP8))
+- **NVFP4-Checkpoints** (Beispiel: [RedHatAI/Qwen3.6-35B-A3B-NVFP4](https://huggingface.co/RedHatAI/Qwen3.6-35B-A3B-NVFP4))
+- **AWQ-INT4-Checkpoints** (Beispielfamilien `...-AWQ` im gleichen Model-Tree)
+
+GGUF-Varianten sind hier bewusst ausgeschlossen, weil dieser Guide auf dediziertes API-Serving abzielt und nicht auf lokale Desktop-Runtimes. Zwar ist theoretisch das Hosting von GGUF-Modellen möglich. Jedoch ist dieses Backend immer noch im Beta Status und nicht für den Produktionsbetrieb empfohlen.
+
+#### Wie Quantisierung dieselbe 1-GPU-Rechnung verändert {#quantization-estimate}
+
+Gleiche Annahmen wie oben:
+
+- 1x RTX PRO 6000 Blackwell (`96 GB`)
+- 20% Sicherheitsreserve -> Planungsbudget ~`80 GB`
+- KV-Cache pro Token (BF16-KV) ~`327.680 bytes`
+- KV-Cache pro Token (FP8-KV) ~`163.840 bytes` (ungefähr halb so groß wie BF16-KV)
+
+Gewichtsspeicher grob nach Format:
+
+- **BF16**: `~72 GB` (36B * 2 Bytes)
+- **FP8**: `~36 GB` (36B * 1 Byte)
+- **4-Bit-Familie (NVFP4/AWQ)**: theoretisch `~18 GB` (+Metadata-/Scale-Overhead, in der Praxis oft höher)
+
+Daraus grober Gesamt-Token-Bereich bei Concurrency 1 (Input + Output):
+
+- **BF16-Gewichte + BF16-KV**: ~`24k-26k` Tokens
+- **BF16-Gewichte + FP8-KV**: ~`49k-52k` Tokens (grob 2x gegenüber BF16-KV)
+- **FP8-Gewichte + BF16-KV**: ~`130k+` Tokens
+- **FP8-Gewichte + FP8-KV**: ~`260k+` Tokens (oft nah an Kontext-Limits des Modells)
+- **4-Bit-Gewichte + BF16-KV**: ~`170k+` Tokens (in der Praxis oft niedriger durch Overhead/Runtime-Limits)
+- **4-Bit-Gewichte + FP8-KV**: potenziell deutlich mehr Tokens, aber meist durch Kontext-Limits und Runtime-Verhalten begrenzt, bevor VRAM voll ausgeschöpft wird
+
+Das ist nur eine Erstplanung. Die final nutzbaren Limits hängen von Checkpoint-Paketierung, KV-Cache-Format-Support, multimodalem Speicherbedarf und Runtime-Verhalten unter Parallelität ab.
+
+#### Schnelle Faustregeln {#quick-rules}
+
+- Längerer Kontext und mehr Parallelität vergrößern den KV-Cache linear.
+- Quantisierung reduziert den Gewichtsspeicher stark, aber bei langem Kontext dominiert häufig der KV-Cache.
+- Liegt die Schätzung nahe am VRAM-Limit, sollte Multi-GPU oder reduzierter Kontext/Concurrency eingeplant werden.
+
+### Quantisierung und Präzisionsformate {#precision-options}
+
+Je nach Modell und Runtime können verschiedene Zahlenformate eingeplant werden, zum Beispiel:
+
+- `BF16` / `FP16` (qualitätsorientiert, höherer Speicherbedarf)
+- `FP8` (häufig guter Tradeoff aus Performance und Kapazität)
+- `NVFP4` / andere Low-Bit-Varianten (maximale Fit-/Durchsatzoptimierung bei sehr großen Modellen)
+
+Welches Format passt, hängt von deinen Qualitätszielen, Latenzvorgaben und der Kontextlänge ab.
+Nicht jedes Modell ist in jedem Quantisierungsformat verfügbar; die Kompatibilität wird pro Modell validiert.
+
+Praxis-Hinweise zur KV-Cache-Quantisierung:
+
+- **FP8-KV-Cache kann in vielen Setups die nutzbare Kontextkapazität gegenüber BF16-KV-Cache grob verdoppeln**.
+- Das funktioniert nur zuverlässig, wenn der verwendete Checkpoint kompatible KV-Scale-Metadaten/Kalibrierung enthält.
+- Fehlen diese Scales, fällt die Runtime ggf. auf BF16-KV-Cache zurück (höherer VRAM-Bedarf) oder zeigt Qualitäts-/Performanceprobleme.
+- Manche Modell-Stacks benötigen BF16-KV-Cache für stabile Ausgabequalität; wir validieren das pro Modell vor dem Produktivbetrieb.
+
+### Modellklassen aus aktuellen Markttrends {#model-classes}
+
+In aktuellen Hugging-Face-Trends sieht man sehr unterschiedliche Klassen, unter anderem:
+
+- kompakte Modelle um `7B-9B`
+- mittlere Modelle um `27B-36B` (inkl. MoE-/A3B-Varianten)
+- große Modelle in `70B+` Klassen
+
+Deshalb ist Dedicated-Sizing immer use-case-spezifisch.
+
+:::note[Sizing immer gemeinsam abstimmen]
+Bitte plane Modell, Präzisionsformat und Kapazität immer im persönlichen Austausch mit uns. Wir validieren Fit, Durchsatz und erstellen ein passgenaues Konzept vor dem Go-Live.
+:::
+
+### Enthaltene Plattformfunktionen {#platform-features}
+
+- Dedizierter Endpunkt und API-Key
+- Router-gesteuerte Lastverteilung über die bereitgestellte Kapazität
+- Automatisches Failover innerhalb deines Dedicated-Setups
+
+### LiteLLM vs Bifrost (wann wofür) {#litellm-vs-bifrost}
+
+Viele Kunden nutzen nicht nur einen einzigen Endpunkt. Wenn du über mehrere Provider oder zusätzliche Self-Hosted-Endpunkte routest, hilft diese Aufteilung:
+
+| Ziel | Empfohlene Komponente |
+|------|------------------------|
+| Keys pro Kunde ausstellen, Keys sperren/löschen, Budgets und Nutzung pro Key | **LiteLLM** |
+| Multi-Provider-Routing, Fallback-Ketten, gewichtete Lastverteilung | **Bifrost** |
+| Governance + Routing über mehrere Endpunkte | **LiteLLM + Bifrost zusammen** |
+
+Typische Muster:
+
+- **Nur dein mittwald Dedicated-Endpunkt + Kunden-Key-Lifecycle**: LiteLLM allein reicht meist aus.
+- **mittwald Dedicated-Endpunkt + weitere externe/self-hosted Modell-Endpunkte**: Bifrost ist für Routing-Richtlinien empfehlenswert.
+- **Dedicated + Shared + Anthropic/Claude (oder weitere Provider)**: Bifrost ist die Routing-Schicht für modell-/provider-spezifische Traffic-Entscheidungen.
+- **Kunden-Keys + Multi-Endpunkt-Routing**: LiteLLM vor Bifrost betreiben.
+: Request-Flow: `client -> LiteLLM -> Bifrost -> ausgewählter Provider-Endpunkt`
+
+### Nicht im initialen Umfang enthalten {#not-included}
+
+- Grafana-/Metrik-Dashboards
+- Self-Service-Provisionierung via mStudio
+
+:::info Einstieg
+Für den Einstieg siehe [Getting started](./getting-started). Für Multi-Key-Management und Nutzungsstatistiken nutze den [LiteLLM-Guide](./litellm).
+:::
+
+