KKiosapi.id

← Dokumentasi

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).

Keamanan: panggil API dari server, bukan dari kode client-side (Blazor WASM dsb.). Simpan key sebagai environment variable / secret manager, jangan hardcode.
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

FreeBerbayar
Rate limit5 req/menit60 req/menit
Kuota harian50 request/hari (reset 07:00 WIB), email terverifikasitanpa batas harian
Output maks~2048 tokensesuai maxOutput model
Input maks~24k karaktersesuai 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.