Skip to main content

routerai

Python wrapper for the RouterAI API — unified access to 450+ AI models (OpenAI, Anthropic, Google, DeepSeek, Qwen, ...) with ruble pricing.

Features

  • OpenAI-compatible chat completions with sync + async support (one client instance supports both; transports are kept separate)
  • Parsed responses: content, reasoning, tool calls, alternatives, token usage and cost in rubles (Decimal)
  • Streaming (SSE) with per-chunk deltas; once a successful response stream is opened no automatic retries happen (even if 0 chunks arrived), mid-stream failures raise a typed StreamInterruptedError
  • Models catalog: listing, client-side search, grouping by capabilities (text, reasoning, vision, image/video/audio generation, speech, transcription, embeddings, rerank, tools)
  • Post-hoc cost lookup by generation id (X-Generation-Id)
  • Multiple API keys via a per-instance Registry (contextvar, thread/async safe)
  • Images, video (polling), audio (TTS/STT), embeddings, rerank, API-key and team management
  • Zero-effort logging via the standard logging module (namespace routerai, keys masked)

Install

pip install routerai

Quickstart

from routerai import RouterAI

client = RouterAI(api_key="sk-...")  # or set ROUTERAI_API_KEY env var

result = client.chat.complete("deepseek/deepseek-v4-pro", "Привет!")
print(result.content)
print(result.cost_rub)  # Decimal, in rubles

Model catalog

client.models.all()                       # full catalog (cached, TTL by default 10 min)
client.models.search("claude", capabilities=["reasoning"], min_context=100_000)
client.models.by_capability("image")      # image generation models
client.models.grouped()                   # dict[Capability, list[Model]]
client.models.get("deepseek/deepseek-v4-pro").pricing.per_million("prompt")
client.models.endpoints("anthropic/claude-sonnet-5")  # providers + prices

Several API keys

from routerai import RouterAI, Registry

registry = Registry(main=RouterAI(api_key=A), personal=RouterAI(api_key=B))
registry["personal"].chat.complete(...)
with registry.using("main"):
    ...

Streaming

for chunk in client.chat.stream("openai/gpt-5.6-sol", "Расскажи сказку"):
    print(chunk.content, end="")

Speech-to-text

client.audio.transcribe("openai/whisper-large-v3", "voice.wav")      # format from suffix
client.audio.transcribe("openai/whisper-large-v3", raw_bytes, format="mp3")
for chunk in client.audio.speech_stream("x-ai/grok-voice-tts-1.0", "текст", voice="eve"):
    ...

Video lifecycle

from routerai import FrameImage, ImageReference

task = client.videos.create(
    "bytedance/seedance-2.0",
    "Персонаж идёт через осенний лес",
    frame_images=[FrameImage(url="https://example.com/first.png", frame_type="first_frame")],
    # or reference-to-video: input_references=[ImageReference(url=...)]
)
task.wait(timeout=600, interval=5)      # absolute deadline, incl. retries
task.save("video.mp4", index=0)         # streaming download, atomic rename
await task.asave("video.mp4")           # async variant, cancellation-safe

# webhooks: verify HMAC over the raw body with your api key
from routerai.webhooks import verify_video
data = verify_video(raw_body, signature, api_key, timestamp, max_age_seconds=300)

Async

result = await client.chat.acomplete("deepseek/deepseek-v4-pro", "Привет!")
async for chunk in client.chat.astream(...):
    ...
await client.aclose()

Sync and async transports live in separate slots, so one instance can serve both modes. Note the lifecycle: close() closes the sync connection pool, await aclose() closes the async one. If a single instance was used from both modes, call both. External transports injected via http_client/async_http_client are never closed by the library.

Configuration

Option Description
api_key / ROUTERAI_API_KEY API key (env var used when argument is None)
base_url / ROUTERAI_BASE_URL base URL; precedence: explicit argument > env var > https://routerai.ru/api/v1
timeout per-request timeout in seconds (default 60)
max_retries retry attempts with exponential backoff + jitter (default 2)
max_retry_after upper bound for an upstream Retry-After header, seconds (default 60)
retry_unsafe_methods retry POST/PATCH/DELETE on 5xx too (default False; RouterAI already
does provider fallback, a client-side POST retry may start a new billed generation)
http_client / async_http_client inject external httpx transports (never closed by the library)

Retries honour the Retry-After header. Safe methods (GET/HEAD) are retried on 429/5xx; unsafe methods only on 429 by default.

The extra parameter is an escape hatch for provider-specific request fields: it can never override library-managed keys (model, messages, stream, ...) — colliding keys raise ValueError.

Errors

Exception HTTP
AuthenticationError 401
InsufficientFundsError 402
PermissionDeniedError 403
NotFoundError 404
RateLimitError 429
NoProviderError 503 with "no provider available"
APIStatusError other 4xx/5xx (has .status_code, .body)
RequestError transport failure after retries
DeadlineExceededError an absolute polling deadline passed (video wait())
StreamInterruptedError SSE broke after the response stream was opened (.chunks_received may be 0)
VideoGenerationError a video task reached failed/cancelled/expired
WebhookVerificationError video webhook failed signature or freshness checks

Logging

import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger("routerai").setLevel(logging.DEBUG)  # API keys are masked

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

routerai-0.1.0.tar.gz (100.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

routerai-0.1.0-py3-none-any.whl (47.0 kB view details)

Uploaded Python 3

File details

Details for the file routerai-0.1.0.tar.gz.

File metadata

  • Download URL: routerai-0.1.0.tar.gz
  • Upload date:
  • Size: 100.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for routerai-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4c82b979bd69a33e9233f7c0025c3ab22e5fd87126af09b376724e1467f419a6
MD5 9ca73d3064263802a95ef42937b56da1
BLAKE2b-256 8d3f33e766372e2969b044aada01086cd4e4b6d5006466a6361cde57906b73c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for routerai-0.1.0.tar.gz:

Publisher: release.yml on alcovegan/routerai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file routerai-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: routerai-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 47.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for routerai-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9095dfbb2df634e63081e855b7a0a5cd68220ba049e8afc8412eb12029b6e16b
MD5 31cdb1f89c5938564b34d745314ce75c
BLAKE2b-256 1a2ce657e107dbb7dc0ce84397d4518bf4e8bb882bb820f4144fc08677d13a77

See more details on using hashes here.

Provenance

The following attestation bundles were made for routerai-0.1.0-py3-none-any.whl:

Publisher: release.yml on alcovegan/routerai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page