@routify-router/sdk
v0.1.0
Published
Official TypeScript SDK for Routify — one API for the world's best AI models (Gemini, DeepSeek, Llama, Kimi, GPT-OSS, Grok, and more).
Maintainers
Readme
@routify-router/sdk
The official TypeScript SDK for Routify — one API for the world's best AI models. Drop‑in OpenAI compatibility with built‑in retries, streaming, and gateway‑exclusive primitives.
npm install @routify-router/sdk
# or
pnpm add @routify-router/sdk
# or
bun add @routify-router/sdk- ⚡ Tiny — under 10 KB minified, zero dependencies
- 🔁 Automatic retries — exponential backoff with jitter, honors
Retry-After - 🌊 Streaming first —
for awaitoverChatCompletionChunks, no SSE plumbing - 🛡 Typed errors —
RateLimitError,InsufficientCreditsError,UpstreamError, etc. - 🎯 OpenAI shape — drop in over the
openaipackage by swapping the import - 🧠 Gateway-exclusive —
compare(),cheapest(),fastest(),route()— no other SDK has these
Quickstart
import { Routify } from "@routify-router/sdk";
const routify = new Routify({ apiKey: process.env.ROUTIFY_API_KEY });
const resp = await routify.chat.completions.create({
model: "gemini-2-5-flash",
messages: [{ role: "user", content: "Write a haiku about latency." }],
});
console.log(resp.choices[0].message.content);Streaming
const stream = await routify.chat.completions.create({
model: "kimi-k2-6",
stream: true,
messages: [{ role: "user", content: "Stream a short story." }],
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}Migrate from openai
Three changes total:
- import OpenAI from "openai";
- const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
+ import { Routify } from "@routify-router/sdk";
+ const client = new Routify({ apiKey: process.env.ROUTIFY_API_KEY });
const r = await client.chat.completions.create({
- model: "gpt-4o-mini",
+ model: "gemini-2-5-flash",
messages: [{ role: "user", content: "Hello" }],
});Everything else — stream, tools, tool_choice, response_format, seed, temperature, function calling — works identically.
Gateway-exclusive primitives
compare() — race N models in parallel
const results = await routify.compare(
["kimi-k2-6", "deepseek-v4-pro", "llama-3-3-70b"],
{ prompt: "Explain dark matter in one paragraph." }
);
for (const r of results) {
console.log(r.model, r.latencyMs + "ms", r.content?.slice(0, 80));
}
// kimi-k2-6 1240ms Dark matter is a hypothesized form of matter…
// deepseek-v4-pro 903ms Dark matter refers to non-luminous, non-baryonic…
// llama-3-3-70b 1760ms Dark matter is one of cosmology's deepest mysteries…Failures are returned in the same array — they don't throw.
cheapest() — pick the lowest-cost model that fits
const model = await routify.cheapest({
capabilities: ["chat", "function_calling"],
minContext: 128_000,
});
console.log("Using", model?.id);fastest() — probe live TTFB and pick a winner
const winner = await routify.fastest({ capabilities: ["chat"] });
console.log(winner); // { model: "llama-3-2-3b", latencyMs: 289 }route() — explicit fallback order
const resp = await routify.route(
["deepseek-v4-pro", "kimi-k2-6", "llama-3-3-70b"],
{ prompt: "..." }
);Tries each model in order, returns the first success, throws the last error if every model fails.
chatText() — one-liner for simple prompts
const text = await routify.chatText("gemini-2-5-flash", "Write a haiku");Embeddings
const vectors = await routify.embeddings.create({
model: "bge-m3",
input: ["First doc", "Second doc"],
});
console.log(vectors.data[0].embedding.slice(0, 4));Voice — TTS
import { writeFile } from "node:fs/promises";
const audio = await routify.audio.speech.create({
model: "aura-2-en",
voice: "asteria",
input: "Welcome to Routify.",
});
await writeFile("hello.mp3", Buffer.from(audio));Voice — STT
import { readFile } from "node:fs/promises";
const bytes = await readFile("recording.mp3");
const transcript = await routify.audio.transcriptions.create({
file: bytes,
filename: "recording.mp3",
model: "whisper-large-v3-turbo",
});
console.log(transcript.text);Error handling
Every failure is a typed subclass of RoutifyError, so you can switch on the kind:
import {
RateLimitError,
InsufficientCreditsError,
AuthError,
RoutifyError,
} from "@routify-router/sdk";
try {
await routify.chat.completions.create({ /* ... */ });
} catch (err) {
if (err instanceof RateLimitError) {
await new Promise((r) => setTimeout(r, err.retryAfterMs ?? 1000));
} else if (err instanceof InsufficientCreditsError) {
console.log("Top up at https://routify.ai/billing");
} else if (err instanceof AuthError) {
console.log("Check ROUTIFY_API_KEY");
} else if (err instanceof RoutifyError) {
console.log(err.status, err.requestId, err.message);
}
}Configuration
const routify = new Routify({
apiKey: process.env.ROUTIFY_API_KEY,
baseURL: "https://api.routify.ai/v1", // override for self-hosting
timeoutMs: 60_000, // default 60s
maxRetries: 3, // 0 = disable retries
defaultHeaders: { "X-My-Header": "v1" },
project: "billing-service", // tag every request in the dashboard
debug: false, // console.debug each attempt
});Per-request overrides:
await routify.chat.completions.create(
{ model, messages },
{
signal: AbortSignal.timeout(5000),
maxRetries: 1,
headers: { "X-Trace-Id": "abc" },
idempotencyKey: "user-123-msg-456",
},
);Edge runtimes
The SDK uses only globalThis.fetch and AbortController, so it runs unmodified on:
- Node.js ≥ 18
- Bun
- Deno
- Cloudflare Workers
- Vercel Edge Functions
- Browser (any modern)
License
MIT © Routify
