Quickstart
Five minutes: grab an API key, install the SDK, ship your first routed call, then open the trace to see the routing decision. Every snippet below is production-shaped — copy it as-is.
Prerequisites
- Node.js 18+, Python 3.9+, or any runtime that can do HTTPS
- A SkyAIApp account (private-beta invite-only — see note below)
- Five minutes and a cup of coffee
Get an API key
Sign into the SkyAIApp Console → Settings → API Keys → New key. Keys look like this:
# Live key — used by your production app
sk_live_01JEXAMPLE4F5G6H7J8K9LMNPQRSTUVWXYZabcdefghi
# Test key — sandbox-mode, never bills, returns canned model output
sk_test_01JEXAMPLE4F5G6H7J8K9LMNPQRSTUVWXYZabcdefghiDo this
- Store in env vars or a secret manager
- Create one key per environment (dev / staging / prod)
- Label each key in the console — easier audits
- Front-end calls go through your own backend proxy — never ship the key to a browser
Don't do this
- Commit keys to git (even private repos)
- Hard-code into client bundles or mobile apps
- DM keys via Slack / WeChat
- Reuse the same key across test and prod
# Linux / macOS — add to ~/.zshrc or use direnv
export SKYAIAPP_API_KEY="sk_live_01JEXAMPLE..."
# Windows PowerShell — for the current session
$env:SKYAIAPP_API_KEY = "sk_live_01JEXAMPLE..."
# .env.local for Next.js / Node — never commit this file
SKYAIAPP_API_KEY=sk_live_01JEXAMPLE...Install the SDK
TypeScript and Python SDKs are GA; Go is in beta; REST works for everything else.
TypeScript / JavaScript
npm install @skyaiapp/sdk
# or
pnpm add @skyaiapp/sdk
# or
yarn add @skyaiapp/sdkWorks on Node ≥ 18, Bun ≥ 1.1, Deno ≥ 1.40. Vercel + Cloudflare Workers edge runtime supported out of the box.
Python
pip install skyaiapp
# or
poetry add skyaiapp
# or
uv add skyaiappPython ≥ 3.9. Native async (built on httpx) plus a sync wrapper.
Go
go get github.com/skyaiapp/skyaiapp-go@latestGo ≥ 1.21. The interface may shift slightly before GA.
REST / cURL
# Nothing to install — just call the API directly.
# Base URL: https://api.skyaiapp.com
# Auth: Authorization: Bearer $SKYAIAPP_API_KEYRuby / PHP / .NET / Rust users go straight to REST — see the SDKs section.
Make your first call
The three snippets below are equivalent — pick whichever language fits. Each one ships with proper error handling, timeouts, and trace inspection.
import { SkyAI, isRouterError, RouterTimeoutError } from "@skyaiapp/sdk";
// One client, reused across requests. The SDK handles connection pooling,
// retry budgets, and trace propagation under the hood.
const sky = new SkyAI({
apiKey: process.env.SKYAIAPP_API_KEY!,
// Optional: pin a routing policy version (created in console).
// policyId: "policy_prod_v3",
// Optional: override the base URL for self-hosted / staging.
// baseURL: "https://api-staging.skyaiapp.com",
});
async function summarize(text: string) {
try {
const res = await sky.route({
goal: "cost", // "cost" | "quality" | "stability"
strategy: "balanced", // "balanced" | "cost-optimized" | "quality-first"
messages: [
{ role: "system", content: "You are a precise summarizer. Output 2 sentences." },
{ role: "user", content: text },
],
// Hard upper bound on per-request spend; router refuses pricier models.
budget: { maxCostUsd: 0.01 },
// Wall-clock timeout — surfaces as RouterTimeoutError.
timeoutMs: 15_000,
// Tag for analytics + per-tenant budgets in the console.
metadata: { tenant: "acme-corp", workflow: "summary" },
});
return {
summary: res.output,
model: res.routing.selectedModel, // e.g. "claude-haiku-4.5"
cost: res.routing.costUsd, // e.g. 0.00021
latency: res.routing.latencyMs, // e.g. 410
cached: res.routing.cacheHit, // boolean
traceId: res.traceId, // open in console
};
} catch (err) {
if (err instanceof RouterTimeoutError) {
// Timeouts are recoverable — retry with a faster model or longer budget.
return null;
}
if (isRouterError(err)) {
// Structured router error — { code, message, retryAfterMs?, upstreamProvider? }
console.error("Router error:", err.code, err.message);
}
throw err;
}
}
const out = await summarize("…paste a 2-page doc here…");
console.log(out);import os
from skyaiapp import SkyAI, RouterError, RouterTimeoutError
sky = SkyAI(api_key=os.environ["SKYAIAPP_API_KEY"])
async def summarize(text: str) -> dict | None:
try:
res = await sky.route(
goal="cost", # "cost" | "quality" | "stability"
strategy="balanced",
messages=[
{"role": "system", "content": "You are a precise summarizer. Output 2 sentences."},
{"role": "user", "content": text},
],
budget={"max_cost_usd": 0.01},
timeout_ms=15_000,
metadata={"tenant": "acme-corp", "workflow": "summary"},
)
except RouterTimeoutError:
return None # recoverable — retry with cheaper model or longer budget
except RouterError as e:
# Structured: e.code, e.message, e.retry_after_ms, e.upstream_provider
print(f"Router error: {e.code} {e.message}")
raise
return {
"summary": res.output,
"model": res.routing.selected_model,
"cost": res.routing.cost_usd,
"latency": res.routing.latency_ms,
"cached": res.routing.cache_hit,
"trace_id": res.trace_id,
}curl https://api.skyaiapp.com/v1/route \
--max-time 15 \
-H "Authorization: Bearer $SKYAIAPP_API_KEY" \
-H "Content-Type: application/json" \
-H "X-SkyAI-Metadata: tenant=acme-corp;workflow=summary" \
-d '{
"goal": "cost",
"strategy": "balanced",
"messages": [
{ "role": "system", "content": "You are a precise summarizer. Output 2 sentences." },
{ "role": "user", "content": "…paste a 2-page doc here…" }
],
"budget": { "max_cost_usd": 0.01 },
"timeout_ms": 15000
}'Inspect the response and trace
Every response includes a trace_id. Search it in the console to see the full decision tree — candidates considered, policy hits, cache lookups, fallbacks.
{
"output": "The document argues that ... [2 sentences].",
"trace_id": "tr_01JFGYZ7K8M2N3P4Q5R6S7T8U9",
"routing": {
"selected_model": "claude-haiku-4.5",
"fallback_chain": ["gpt-5.5-mini", "deepseek-v4-pro"],
"cost_usd": 0.00021,
"latency_ms": 410,
"cache_hit": false,
"policy_version": "policy_prod_v3@2026-05-12",
"tokens": {
"input": 1842,
"output": 64,
"cached": 0
},
"decision_reason": "balanced + cost goal: claude-haiku-4.5 wins on $/quality vs alternatives in this price band."
},
"usage": { "rate_limit_remaining": 4998 }
}🎮 Try it in the browser
Adjust goal and strategy and watch the routing decision update. Output is a simulated decision flow during private beta — real production traces ship at public beta.
Interactive API playground
Click to see routing in action
Response
import { SkyAI } from "@skyaiapp/sdk";
const sky = new SkyAI({
apiKey: process.env.SKYAIAPP_API_KEY
});
const response = await sky.route({
goal: "cost",
strategy: "balanced",
messages: [
{ role: "user", content: "Explain quantum computing in simple terms" }
]
});Before you ship to production
Vault / AWS SSM / 1Password CLI / Doppler all work. Never hard-code or commit.
Security guideOne key per environment, bound to different policy versions in the console.
Team managementAt minimum: tenant and workflow. Lets you slice traces and billing in the console.
ObservabilityUser-facing paths need ≥ 2 fallback tiers; batch jobs can be more aggressive on cost.
Routing strategiesUse sk_test_ keys to hit the sandbox, or wire up the SDK's mock client for unit tests.
Testing & mockingPipe router.fallback_triggered, router.budget_exceeded, etc. into Slack / PagerDuty.
WebhooksNext steps
Stuck?
Send us the trace_id — the founding team replies within one business day and digs to root cause.
Was this page helpful?
Let us know how we can improve