Panduan C# / .NET
Kiosapi kompatibel OpenAI lewat REST biasa. Contoh di bawah pakai System.Net.Http.HttpClient + System.Text.Json bawaan .NET (tanpa NuGet tambahan).
Daftar isi
1. Persiapan
Masuk ke dashboard → Kunci API, beri nama, klik Buat key, salin kios_live_… (ditampilkan sekali).
export KIOSAPI_API_KEY="kios_live_xxxxxxxxxxxx"2. Fungsi helper request
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Nodes;
public static class Kiosapi
{
const string Base = "https://api.kiosapi.id/v1";
static readonly string ApiKey = Environment.GetEnvironmentVariable("KIOSAPI_API_KEY")!;
static readonly HttpClient Http = new();
public static async Task<JsonNode> PostAsync(string path, object body)
{
using var req = new HttpRequestMessage(HttpMethod.Post, Base + path)
{
Content = JsonContent.Create(body),
};
req.Headers.Add("Authorization", $"Bearer {ApiKey}");
var res = await Http.SendAsync(req);
var text = await res.Content.ReadAsStringAsync();
if (!res.IsSuccessStatusCode)
throw new Exception($"Kiosapi error {(int)res.StatusCode}: {text}");
return JsonNode.Parse(text)!;
}
public static async Task<JsonNode> GetAsync(string path)
{
using var req = new HttpRequestMessage(HttpMethod.Get, Base + path);
req.Headers.Add("Authorization", $"Bearer {ApiKey}");
var res = await Http.SendAsync(req);
return JsonNode.Parse(await res.Content.ReadAsStringAsync())!;
}
}Model ID berformat provider/nama-model — lihat daftar lengkap via GET /v1/models atau /pricing.
3. Chat completion dasar
var resp = await Kiosapi.PostAsync("/chat/completions", new
{
model = "anthropic/claude-sonnet-4-6",
messages = new object[]
{
new { role = "system", content = "Kamu asisten yang ringkas dan ramah." },
new { role = "user", content = "Jelaskan apa itu RAG dalam 2 kalimat." },
},
});
Console.WriteLine(resp["choices"]![0]!["message"]!["content"]);
Console.WriteLine($"Token dipakai: {resp["usage"]!["total_tokens"]}");4. Streaming
Tambahkan stream: true dan baca respons baris demi baris (SSE).
using var req = new HttpRequestMessage(HttpMethod.Post, "https://api.kiosapi.id/v1/chat/completions")
{
Content = JsonContent.Create(new
{
model = "deepseek/deepseek-v4-flash",
messages = new[] { new { role = "user", content = "Tulis puisi pendek tentang hujan di Jakarta." } },
stream = true,
}),
};
req.Headers.Add("Authorization", $"Bearer {Environment.GetEnvironmentVariable("KIOSAPI_API_KEY")}");
using var http = new HttpClient();
using var res = await http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead);
using var stream = await res.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (!line.StartsWith("data: ") || line == "data: [DONE]") continue;
var chunk = JsonNode.Parse(line[6..]);
var delta = chunk?["choices"]?[0]?["delta"]?["content"]?.ToString();
if (!string.IsNullOrEmpty(delta)) Console.Write(delta);
}Model reasoning (🧠) bisa mengirim delta reasoning_content terpisah dari content — cek field itu di JSON delta untuk status "sedang berpikir".
5. Tool calling / function calling
Format sama persis OpenAI — didukung untuk model bertanda 🔧 di katalog, termasuk Claude & Gemini (diterjemahkan otomatis oleh gateway).
var tools = new object[]
{
new
{
type = "function",
function = new
{
name = "get_weather",
description = "Ambil cuaca terkini untuk sebuah kota",
parameters = new
{
type = "object",
properties = new { city = new { type = "string", description = "Nama kota" } },
required = new[] { "city" },
},
},
},
};
var messages = new List<object> { new { role = "user", content = "Cuaca di Bandung sekarang gimana?" } };
var resp = await Kiosapi.PostAsync("/chat/completions", new { model = "openai/gpt-4o", messages, tools });
var msg = resp["choices"]![0]!["message"]!;
if (msg["tool_calls"] is JsonArray calls)
{
foreach (var call in calls)
{
var name = call!["function"]!["name"];
var args = call["function"]!["arguments"];
Console.WriteLine($"Model minta panggil: {name} {args}");
messages.Add(msg);
messages.Add(new
{
role = "tool",
tool_call_id = call["id"]!.ToString(),
content = JsonSerializer.Serialize(new { suhu_celsius = 27, kondisi = "berawan" }),
});
}
var followup = await Kiosapi.PostAsync("/chat/completions", new { model = "openai/gpt-4o", messages });
Console.WriteLine(followup["choices"]![0]!["message"]!["content"]);
}6. Vision (kirim gambar ke model)
Kirim gambar lewat content berbentuk array (image_url + text) — format persis yang dipakai perintah lihat di Kiosapi CLI.
var b64 = Convert.ToBase64String(await File.ReadAllBytesAsync("foto.jpg"));
var resp = await Kiosapi.PostAsync("/chat/completions", new
{
model = "google/gemini-2.5-flash", // pilih model yang mendukung vision
messages = new object[]
{
new
{
role = "user",
content = new object[]
{
new { type = "text", text = "Ada apa saja di foto ini?" },
new { type = "image_url", image_url = new { url = $"data:image/jpeg;base64,{b64}" } },
},
},
},
});
Console.WriteLine(resp["choices"]![0]!["message"]!["content"]);Catatan: fitur ini sudah jalan di level API/CLI. Tombol upload gambar langsung di dashboard web belum tersedia.
7. Structured output / JSON mode
response_format diteruskan langsung ke provider upstream — jalan penuh untuk model yang mendukungnya secara native. Belum ada lapisan pemaksaan JSON yang seragam untuk semua model di katalog.
var resp = await Kiosapi.PostAsync("/chat/completions", new
{
model = "openai/gpt-4o",
messages = new[] { new { role = "user", content = "Beri saya data profil singkat dalam JSON: nama, umur." } },
response_format = new { type = "json_object" },
});
var data = JsonNode.Parse(resp["choices"]![0]!["message"]!["content"]!.ToString());
Console.WriteLine(data);8. Embeddings
var resp = await Kiosapi.PostAsync("/embeddings", new
{
model = "openai/text-embedding-3-small",
input = "Selamat datang di Kiosapi!",
});
var vector = resp["data"]![0]!["embedding"]!.AsArray();
Console.WriteLine($"{vector.Count} dimensi");9. Daftar model & cek saldo
var models = await Kiosapi.GetAsync("/models");
// Saldo & kuota gratis harian (endpoint khusus Kiosapi)
var saldo = await Kiosapi.GetAsync("/saldo");
Console.WriteLine(saldo);10. Endpoint khusus Kiosapi
Bentuknya beda dari chat completions standar, tapi tetap lewat helper Kiosapi.PostAsync/Kiosapi.GetAsync yang sama.
Gambar — POST /v1/images/generations (sinkron)
var img = await Kiosapi.PostAsync("/images/generations", new
{
model = "google/imagen-3",
prompt = "kucing oranye memakai topi koki, fotorealistik",
option = "standard",
n = 1,
});
var b64 = img["data"]![0]!["b64_json"]!.ToString();
await File.WriteAllBytesAsync("hasil.png", Convert.FromBase64String(b64));
Console.WriteLine($"Biaya: {img["kiosapi"]!["cost_rupiah"]} rupiah");Video — POST /v1/videos/generations (asinkron, perlu polling)
var submit = await Kiosapi.PostAsync("/videos/generations", new
{
model = "alibaba/wan2.7-t2v",
prompt = "ombak pantai saat matahari terbenam, sinematik",
option = "standard",
duration_seconds = 5,
});
var jobId = submit["job_id"]!.ToString();
JsonNode job;
do
{
await Task.Delay(5000);
job = await Kiosapi.GetAsync($"/jobs/{jobId}");
} while (job["status"]!.ToString() == "running");
if (job["status"]!.ToString() == "succeeded") Console.WriteLine($"Video siap: {job["video_url"]}");
else Console.WriteLine($"Gagal: {job["error"]}");Image-to-video: sertakan image (base64) + image_mime di body request.
Musik — POST /v1/music/generations
var resp = await Kiosapi.PostAsync("/music/generations", new
{
model = "minimax/music-2.6",
prompt = "pop akustik Indonesia yang hangat, vokal wanita",
lyrics = "[Verse]\nPagi cerah di kota\n[Chorus]\nBersama kita bisa",
});
// poll GET /jobs/{resp["job_id"]} sampai status "succeeded" → field "audio_url"Text-to-speech — POST /v1/audio/speech
using var req = new HttpRequestMessage(HttpMethod.Post, "https://api.kiosapi.id/v1/audio/speech")
{
Content = JsonContent.Create(new
{
model = "minimax/speech-2.8-turbo",
input = "Selamat datang di Kiosapi!",
voice = "Indonesian_CalmWoman", // 9 suara asli Indonesia (model MiniMax)
}),
};
req.Headers.Add("Authorization", $"Bearer {Environment.GetEnvironmentVariable("KIOSAPI_API_KEY")}");
using var http = new HttpClient();
var res = await http.SendAsync(req);
await File.WriteAllBytesAsync("suara.mp3", await res.Content.ReadAsByteArrayAsync());Reranking — POST /v1/rerank (bentuk Cohere, self-hosted)
var res = await Kiosapi.PostAsync("/rerank", new
{
model = "baai/bge-reranker-base",
query = "apa itu kucing?",
documents = new[]
{
"Kucing adalah hewan mamalia berkaki empat.",
"Mobil listrik semakin populer di Indonesia.",
},
return_documents = true,
});
foreach (var r in res["results"]!.AsArray())
Console.WriteLine($"{r!["index"]}: {r["relevance_score"]}");Vector DB — POST /v1/vector-indexes/... (bentuk Pinecone, self-hosted)
// 1) Bikin index (gratis)
await Kiosapi.PostAsync("/vector-indexes", new { name = "artikel-saya" });
// 2) Buat embedding lalu upsert (values wajib 1536 angka, cocok text-embedding-3-small)
var emb = await Kiosapi.PostAsync("/embeddings", new { model = "openai/text-embedding-3-small", input = "Isi artikel di sini" });
var vector = emb["data"]![0]!["embedding"]!;
await Kiosapi.PostAsync("/vector-indexes/artikel-saya/vectors/upsert", new
{
vectors = new object[] { new { id = "artikel-1", values = vector, metadata = new { kategori = "berita" } } },
});
// 3) Cari yang paling relevan
var hasil = await Kiosapi.PostAsync("/vector-indexes/artikel-saya/query", new
{
vector, top_k = 5, include_metadata = true,
});
Console.WriteLine(hasil["matches"]);11. Penanganan error
try
{
var resp = await Kiosapi.PostAsync("/chat/completions", new
{
model = "openai/gpt-4o",
messages = new[] { new { role = "user", content = "Halo!" } },
});
}
catch (Exception e)
{
// Kiosapi.PostAsync sudah membungkus status HTTP >= 400 sebagai exception
Console.Error.WriteLine(e.Message);
}Kode HTTP umum: 401 API key salah, 400 model tak dikenal/parameter salah, 402 saldo kurang atau batas pengeluaran bulanan tercapai, 422 ditolak moderasi, 429 rate limit, 502/504 provider upstream bermasalah/timeout. Kode error media lengkap ada di /docs.
12. Rate limit & kuota
| Free | Berbayar | |
|---|---|---|
| Rate limit | 5 req/menit | 60 req/menit |
| Kuota harian | 50 request/hari (reset 07:00 WIB), email terverifikasi | tanpa batas harian |
| Output maks | ~2048 token | sesuai maxOutput model |
| Input maks | ~24k karakter | sesuai kapasitas model |
13. Contoh lengkap — mini pipeline RAG
Menggabungkan embeddings + vector DB + chat dalam satu alur.
async Task<JsonNode> EmbedAsync(string text)
{
var r = await Kiosapi.PostAsync("/embeddings", new { model = "openai/text-embedding-3-small", input = text });
return r["data"]![0]!["embedding"]!;
}
// Index dokumen (sekali saja)
await Kiosapi.PostAsync("/vector-indexes", new { name = "basis-pengetahuan" });
var dokumen = new[] { "Kiosapi adalah AI API gateway Indonesia.", "Kiosapi mendukung 100+ model AI." };
var vectors = new List<object>();
for (int i = 0; i < dokumen.Length; i++)
{
vectors.Add(new { id = $"doc-{i}", values = await EmbedAsync(dokumen[i]), metadata = new { text = dokumen[i] } });
}
await Kiosapi.PostAsync("/vector-indexes/basis-pengetahuan/vectors/upsert", new { vectors });
// Query + jawab pakai konteks yang relevan
var pertanyaan = "Apa itu Kiosapi?";
var hasil = await Kiosapi.PostAsync("/vector-indexes/basis-pengetahuan/query", new
{
vector = await EmbedAsync(pertanyaan), top_k = 2, include_metadata = true,
});
var konteks = string.Join("\n", hasil["matches"]!.AsArray().Select(m => m!["metadata"]!["text"]!.ToString()));
var jawaban = await Kiosapi.PostAsync("/chat/completions", new
{
model = "anthropic/claude-sonnet-4-6",
messages = new object[]
{
new { role = "system", content = $"Jawab berdasar konteks ini:\n{konteks}" },
new { role = "user", content = pertanyaan },
},
});
Console.WriteLine(jawaban["choices"]![0]!["message"]!["content"]);Referensi lain: spesifikasi OpenAPI 3.1 lengkap, harga & daftar model di /pricing, dan dokumentasi utama di /docs.