Developer Dashboard

Connect 9Router to AvalAI

9Router can register AvalAI as an OpenAI-compatible upstream, assign it a model prefix, and expose the resulting models through a local OpenAI-compatible gateway. This guide keeps the first connection simple, separates Chat Completions from Responses, and delays fallback and request transformations until the direct path is proven.

Validated: The public labels, environment contract, and container paths on this page were checked against official 9Router sources on 2026-08-06. Recheck the AvalAI model catalog and the upstream release before deployment.

What this integration is

The request flow is:

OpenAI-compatible client → local 9Router /v1 gateway → prefixed AvalAI provider node → AvalAI

The AvalAI key authenticates 9Router to AvalAI. A different key generated in the 9Router dashboard authenticates your downstream client to 9Router. Do not reuse or confuse these two credentials.

Use 9Router when you need a local gateway, prefixed model IDs, multiple upstream connections, priorities, or controlled fallback. Connect directly to AvalAI when you do not need another routing layer.

What you need

  • Node.js 20+ and npm for the local evaluation path, or Docker with Compose for the durable path.
  • A dedicated AvalAI API key.
  • A current model ID and its supported endpoint.
  • A strong dashboard password and independent random values for the 9Router signing secrets.
  • Local access to http://localhost:20128; do not expose the dashboard before changing its credentials.

The current pilot is gpt-5.4-mini. It supports both Chat Completions and Responses, but those are separate 9Router provider-node types.

Preflight AvalAI

Confirm these values first:

CheckRequired value
AvalAI base URLhttps://api.avalai.ir/v1
Chat route/v1/chat/completions
Responses route/v1/responses
Pilot modelgpt-5.4-mini
Gateway URL after setuphttp://localhost:20128/v1

A successful Check proves only the entered upstream key, URL, API type, and optional model at that moment. It does not create the persistent API-key connection used for later requests.

AvalAI does not currently support the gpt-transcribe or gpt-live-transcribe identifiers. Speech connections must use a model currently listed for the matching /v1/audio/* route.

Install 9Router

For a local evaluation, use the official npm package:

bash
npm install -g 9router
9router

Open http://localhost:20128. For an operational instance, skip the global package and use the pinned Compose example below.

Connect AvalAI

Create the provider node

  1. Open Providers.
  2. Choose Add OpenAI Compatible.
  3. Set Name to AvalAI.
  4. Set Prefix to avalai. The prefix becomes part of every downstream model ID.
  5. Choose Chat Completions for the first connection. Create a separate node with Responses API only when the selected model supports /v1/responses.
  6. Set Base URL to https://api.avalai.ir/v1.
  7. Enter the AvalAI key in API Key (for Check).
  8. Optionally enter gpt-5.4-mini in Model ID (optional).
  9. Select Check, review the result, and create the node.

The validation key is intentionally transient. Continue to the next step.

Add the persistent upstream connection

Open the new AvalAI provider and its Connections card, then select Add Connection. Enter:

  • Name: a descriptive name such as AvalAI production;
  • API Key: the dedicated AvalAI key;
  • Priority: 1 for the first and only connection;
  • Proxy Pool: None unless you have a separately reviewed outbound proxy requirement.

Select Validate, then Save. Confirm that the connection is active before adding another key, round-robin, or fallback.

Understand prefixed model IDs

With prefix avalai, the downstream gateway model is avalai/gpt-5.4-mini, not the bare AvalAI ID. Create a downstream 9Router API key in the dashboard, then inspect the local model list:

bash
curl http://localhost:20128/v1/models \
  -H "Authorization: Bearer replace-with-9router-key"

The client sends the 9Router key to localhost; 9Router sends the saved AvalAI key upstream.

Verify the first flow

Keep one active AvalAI connection and disable fallback while verifying:

bash
curl -N http://localhost:20128/v1/chat/completions \
  -H "Authorization: Bearer replace-with-9router-key" \
  -H "Content-Type: application/json" \
  -H "X-9Router-Token-Saver: off" \
  -d '{
    "model": "avalai/gpt-5.4-mini",
    "messages": [{"role": "user", "content": "Reply with exactly: AvalAI via 9Router"}],
    "stream": true
  }'

Verify these layers separately:

  1. Provider-node Check succeeds.
  2. The persistent connection shows active status.
  3. /v1/models includes the prefixed model.
  4. The streaming Chat Completions request returns the expected model output.
  5. Only then enable token savers, request rewrites, round-robin, proxy pools, or fallback.
  6. For Responses, repeat the process with a distinct Responses API node and /v1/responses request.

The header X-9Router-Token-Saver: off bypasses token savers for one diagnostic request. It helps distinguish an upstream protocol problem from a transformation problem.

Supported capabilities

The generic language-model node covers only the API type selected when that node was created.

StatusCapabilityWhat to expect
DirectModel discovery9Router exposes its routed and prefixed catalog through local /v1/models.
DirectChat CompletionsChoose Chat Completions and call local /v1/chat/completions.
DirectResponsesChoose Responses API in a separate node; the AvalAI model must support the route.
Model/route dependentStreamingThe selected model, upstream route, 9Router adapter, and downstream client must agree on stream framing.
Model/route dependentTools and structured outputRequires model support and compatible pass-through of tools, tool_choice, and schema fields.
Model/route dependentVision/image inputRequires an AvalAI vision model and a downstream client that sends the correct multimodal shape.
Separate configurationEmbeddingsAdd a Self-hosted Embedding connection with base https://api.avalai.ir/v1, a saved key, and a current embeddings model such as text-embedding-v4.
Separate configurationSpeech-to-textAdd a Self-hosted STT connection with the full URL https://api.avalai.ir/v1/audio/transcriptions and a current transcription model.
Separate configurationText-to-speechAdd a Self-hosted TTS connection using server root https://api.avalai.ir so the adapter appends /v1/audio/speech; choose a current speech model.
Separate configurationWeb search9Router web-search providers and the model's own web-search route are different configurations. Verify which one the downstream client invokes.
Unsupported or unvalidatedImage generation, Realtime, and video through the generic nodeNo AvalAI mapping was validated merely from the language provider. Do not infer these routes from OpenAI compatibility.

The labels Self-hosted STT, Self-hosted TTS, and Self-hosted Embedding are 9Router provider types. Their configurable URL and key fields expose the documented OpenAI-shaped route, but this guide did not run credentialed AvalAI media requests through them.

Run with Docker Compose

The official image is multi-platform. Pin a reviewed release, bind the dashboard to loopback, persist /app/data, and omit the optional Headroom sidecar from the baseline:

yaml
services:
  9router:
    image: decolua/9router:v0.5.35
    container_name: 9router
    restart: unless-stopped
    ports:
      - "127.0.0.1:20128:20128"
    volumes:
      - 9router-data:/app/data
    env_file:
      - .env
    environment:
      DATA_DIR: /app/data
      PORT: "20128"
      HOSTNAME: 0.0.0.0
      NODE_ENV: production
      ENABLE_REQUEST_LOGS: "false"

volumes:
  9router-data:

Create an ignored .env with mode 0600. Generate every secret independently; do not use the example text as a real value:

dotenv
JWT_SECRET=replace-with-an-independent-random-value
INITIAL_PASSWORD=replace-with-a-strong-dashboard-password
API_KEY_SECRET=replace-with-an-independent-random-value
MACHINE_ID_SALT=replace-with-an-independent-random-value
DATA_DIR=/app/data
ENABLE_REQUEST_LOGS=false
AUTH_COOKIE_SECURE=false
REQUIRE_API_KEY=true

The upstream fallback for an unset INITIAL_PASSWORD is 123456. Treat that as insecure: set the variable before the first start and never expose an instance using the fallback. Set AUTH_COOKIE_SECURE=true when the dashboard is served through HTTPS.

Start and inspect the pinned instance:

bash
chmod 600 .env
docker compose config --quiet
docker compose up -d
docker compose logs --tail=100 9router

This baseline does not start Headroom, an outbound proxy, or a reverse proxy. Add those only after the direct AvalAI path works and their security boundary is reviewed.

Operate safely

  • Keep port 20128 on loopback or a private network unless an authenticated TLS ingress is already present.
  • Keep the dashboard login, downstream gateway keys, and AvalAI upstream keys separate.
  • Leave ENABLE_REQUEST_LOGS=false for sensitive workloads. Debug logs can contain prompts, responses, headers, files, and personal data.
  • Use a dedicated AvalAI key per 9Router deployment and monitor provider-side usage. The dashboard cost figures are estimates for display and tracking, not AvalAI billing records.
  • Disable token savers and rewrites when diagnosing protocol behavior, then re-enable them one at a time.
  • Protect the volume because it contains SQLite state, backups, certificates, logs, runtime configuration, saved provider credentials, and generated downstream keys.

Before an upgrade, stop the service and copy the durable data out of the stopped container:

bash
docker compose stop 9router
mkdir -p backup/9router-data
docker cp 9router:/app/data/. backup/9router-data/
docker compose start 9router

Record the current image tag. To upgrade, change only the reviewed tag, run docker compose config --quiet, pull, and recreate the service with the same volume. To roll back, restore the previous image tag first. Restore SQLite data only while the service is stopped and only from a tested backup.

Troubleshooting

SymptomCheck this layer firstSafe next action
Provider Check returns 401/403AvalAI key in the transient validation fieldVerify the dedicated upstream key without exposing it.
Local /v1 returns 401/403Downstream 9Router keyUse the gateway key copied from 9Router, not the AvalAI key.
Check succeeds but requests failMissing or inactive persistent connectionAdd the key under Connections, validate, save, and confirm active status.
Model not foundMissing avalai/ prefix or wrong API-type nodeInspect local /v1/models and use its exact model ID.
404 upstreamBase URL or route mismatchKeep https://api.avalai.ir/v1 and match Chat vs Responses.
Stream stalls or output changesToken saver, rewrite, fallback, or proxySend one request with X-9Router-Token-Saver: off and disable other transformations.
Embeddings return 404Base URL missing /v1For Self-hosted Embedding, use https://api.avalai.ir/v1.
STT/TTS route is doubledWrong full-URL vs server-root shapeSTT takes the full transcription URL; TTS takes the server root.
State disappears after restartMissing /app/data volume or wrong DATA_DIRConfirm DATA_DIR=/app/data and the named volume mount.
Dashboard shows high costEstimate confused with billingCheck the AvalAI usage/pricing source; do not treat the 9Router estimate as an invoice.

AvalAI:

9Router:

Validation boundary

This guide was source-reviewed on 2026-08-06. The provider labels, route shapes, release tag, Markdown parity, and Compose syntax can be checked without credentials. This work did not install 9Router, pull or start its image, create a provider node, save an AvalAI key, send a live request, test fallback, restore SQLite, or expose a production gateway. Revalidate the upstream release and current AvalAI routes before operational use.