Stablev1
REST API
Works from any runtime that can make HTTPS calls
Ruby / PHP / .NET / Rust / Java / shell users go straight to REST. All endpoints + parameter tables live in the API Reference; this page provides language examples.
Base information
Base URL
https://api.skyaiapp.comSandbox
https://api-sandbox.skyaiapp.comAuth
Authorization: Bearer $KEYContent-Type
application/json; UTF-8TLS
TLS 1.2+Timestamps
RFC 3339 (UTC)Authentication
Authorization: Bearer sk_live_01JEXAMPLE...
# Sandbox / CI:
Authorization: Bearer sk_test_01JEXAMPLE...Key handling details (rotation, leaks): Security guide。
POST /v1/route
curl https://api.skyaiapp.com/v1/route \
-H "Authorization: Bearer $SKYAIAPP_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: req_$(date +%s)" \
-d '{
"goal": "quality",
"strategy": "quality-first",
"messages": [
{ "role": "system", "content": "You are a senior travel planner." },
{ "role": "user", "content": "Plan a 7-day European trip in October." }
],
"fallback": { "models": ["claude-opus-4.7", "gemini-3.1-pro"], "maxRetries": 2 },
"budget": { "maxCostUsd": 0.05 },
"cache": true,
"timeout_ms": 30000,
"metadata": { "tenant": "acme-corp", "workflow": "trip-planner" }
}'Full parameter table and response schema: API Reference · Routing。
More endpoints
GET /v1/modelsList routable models with pricing, context window, regions.POST /v1/agents/runRun a multi-step agent.GET /v1/traces/{id}Fetch a single trace's full span tree.GET /v1/traces?from=&to=&filter=Filter traces by window / metadata (cursor paginated).GET /v1/analytics/usageUsage, cost, token counts.GET /v1/analytics/cacheCache hit rate + dollars saved.
Language examples
Ruby (Net::HTTP)
require "net/http"
require "json"
uri = URI("https://api.skyaiapp.com/v1/route")
req = Net::HTTP::Post.new(uri, {
"Authorization" => "Bearer #{ENV['SKYAIAPP_API_KEY']}",
"Content-Type" => "application/json",
"Idempotency-Key" => "req_#{Time.now.to_i}",
})
req.body = {
goal: "cost", strategy: "balanced",
messages: [{ role: "user", content: "Hello!" }],
budget: { maxCostUsd: 0.01 },
timeout_ms: 15_000,
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
abort "HTTP #{res.code}: #{res.body}" unless res.is_a?(Net::HTTPSuccess)
data = JSON.parse(res.body)
puts data.dig("routing", "selected_model"), data["output"]PHP (Guzzle)
<?php
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.skyaiapp.com', 'timeout' => 30]);
try {
$res = $client->post('/v1/route', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('SKYAIAPP_API_KEY'),
'Idempotency-Key' => 'req_' . time(),
],
'json' => [
'goal' => 'quality',
'strategy' => 'balanced',
'messages' => [['role' => 'user', 'content' => 'Hello!']],
'budget' => ['maxCostUsd' => 0.01],
'timeout_ms'=> 15000,
],
]);
$data = json_decode($res->getBody(), true);
echo $data['routing']['selected_model'] . PHP_EOL . $data['output'];
} catch (\GuzzleHttp\Exception\ClientException $e) {
$err = json_decode($e->getResponse()->getBody(), true);
error_log("router error: " . $err['error']['code'] . " trace=" . $err['error']['trace_id']);
throw $e;
}.NET / C#
using System.Net.Http.Json;
var http = new HttpClient { BaseAddress = new Uri("https://api.skyaiapp.com") };
http.DefaultRequestHeaders.Authorization =
new("Bearer", Environment.GetEnvironmentVariable("SKYAIAPP_API_KEY"));
var req = new {
goal = "cost", strategy = "balanced",
messages = new[] { new { role = "user", content = "Hello!" } },
budget = new { maxCostUsd = 0.01 },
timeout_ms = 15_000,
};
using var msg = new HttpRequestMessage(HttpMethod.Post, "/v1/route") {
Content = JsonContent.Create(req),
};
msg.Headers.Add("Idempotency-Key", $"req_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}");
var res = await http.SendAsync(msg);
res.EnsureSuccessStatusCode();
var body = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(body.GetProperty("routing").GetProperty("selected_model"));Rust (reqwest)
use reqwest::Client;
use serde_json::json;
let client = Client::new();
let res: serde_json::Value = client
.post("https://api.skyaiapp.com/v1/route")
.bearer_auth(std::env::var("SKYAIAPP_API_KEY")?)
.header("Idempotency-Key", format!("req_{}", chrono::Utc::now().timestamp()))
.json(&json!({
"goal": "quality",
"strategy": "balanced",
"messages": [{ "role": "user", "content": "Hello!" }],
"budget": { "maxCostUsd": 0.01 },
"timeout_ms": 15_000,
}))
.timeout(std::time::Duration::from_secs(30))
.send().await?
.error_for_status()?
.json().await?;
println!("model = {}", res["routing"]["selected_model"]);Recommended practices
- Always send Idempotency-Key — protects against double-billing on retries.
- Always set timeout_ms (≤ 30s for user-facing; batch jobs can go higher).
- Always log error.code and error.trace_id.
- Do not retry on 4xx (except 408 / 429).
- Use sk_test_ keys + sandbox URL for integration tests.
See also
Was this page helpful?
Let us know how we can improve