Panduan API

DRouter kompatibel penuh dengan format OpenAI Chat Completions. Kalau kode kamu sudah jalan dengan OpenAI, cuma perlu ganti base_url dan api_key.

01 Mulai cepat

Tiga langkah dari nol sampai respons pertama. Butuh satu API key - ambil lewat bot Telegram, bayar pakai QRIS, key langsung aktif.

bash
# 1. Simpan key kamu
export DROUTER_KEY="dr-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# 2. Tes koneksi - daftar model yang tersedia
curl https://drouter.web.id/v1/models \
  -H "Authorization: Bearer $DROUTER_KEY"

# 3. Kirim pesan pertama
curl https://drouter.web.id/v1/chat/completions \
  -H "Authorization: Bearer $DROUTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "cybernetic",
    "messages": [{"role": "user", "content": "Halo, perkenalkan diri singkat."}]
  }'
Base URL

https://drouter.web.id/v1 - tambahkan /chat/completions untuk chat, /models untuk daftar model.

02 Autentikasi

Setiap request wajib menyertakan API key di header Authorization dengan skema Bearer.

http
Authorization: Bearer dr-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type:  application/json

Aturan key

Jangan expose key

Key = identitas akun. Jangan taruh di kode frontend, repo publik, atau screenshot. Kalau bocor, minta ganti lewat bot.

03 Chat completions

Endpoint utama. Format request dan response sama persis dengan OpenAI Chat Completions API.

POST /v1/chat/completions Kirim percakapan, terima balasan model. Butuh auth.
GET /v1/models Daftar model yang bisa diakses key kamu. Butuh auth.
GET /api/me Status key + statistik pemakaian. Butuh auth.
GET /health Cek gateway hidup. Publik, tanpa auth.

Body request

modelstring WAJIB Nama model. Pilihan: cybernetic atau unrestmes. Lihat daftar model.
messagesarray WAJIB Riwayat percakapan. Tiap item punya role (system / user / assistant) dan content.
temperaturenumber OPSIONAL Tingkat keacakan, 0 sampai 2. Default dari upstream.
max_tokensinteger OPSIONAL Batas panjang balasan dalam token.
top_pnumber OPSIONAL Nucleus sampling. Biasanya dipakai sebagai alternatif temperature.
streamboolean OPSIONAL Belum didukung - nilai ini diabaikan, response selalu utuh.

Body response

json
{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1793230368,
  "model": "cybernetic",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Halo. Saya siap membantu."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 18,
    "completion_tokens": 42,
    "total_tokens": 60
  }
}
Field model

Field model di response selalu berisi nama model yang kamu minta - bukan nama model internal. Yang kamu kirim, itu yang kamu terima.

04 Contoh kode

Pilih bahasa. Semua contoh jalan apa adanya - ganti DROUTER_KEY dengan key kamu.

bash
curl https://drouter.web.id/v1/chat/completions \
  -H "Authorization: Bearer $DROUTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "cybernetic",
    "messages": [
      {"role": "system", "content": "Kamu asisten teknis yang to the point."},
      {"role": "user", "content": "Jelaskan apa itu rate limit."}
    ],
    "temperature": 0.7,
    "max_tokens": 500
  }'
python
# pip install requests
import os, requests

KEY = os.environ["DROUTER_KEY"]
URL = "https://drouter.web.id/v1/chat/completions"

resp = requests.post(
    URL,
    headers={
        "Authorization": f"Bearer {KEY}",
        "Content-Type": "application/json",
    },
    json={
        "model": "cybernetic",
        "messages": [
            {"role": "user", "content": "Tulis fungsi Python untuk cek bilangan prima."}
        ],
    },
    timeout=120,
)

if resp.status_code != 200:
    raise SystemExit(f"HTTP {resp.status_code}: {resp.text[:300]}")

data = resp.json()
print(data["choices"][0]["message"]["content"])
print("token:", data["usage"]["total_tokens"])
javascript
// Node.js 18+ (fetch sudah bawaan)
const KEY = process.env.DROUTER_KEY;
const URL = "https://drouter.web.id/v1/chat/completions";

const resp = await fetch(URL, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "unrestmes",
    messages: [{ role: "user", content: "Ringkas berita teknologi hari ini." }],
  }),
});

if (!resp.ok) {
  throw new Error(`HTTP ${resp.status}: ${await resp.text()}`);
}

const data = await resp.json();
console.log(data.choices[0].message.content);
console.log("token:", data.usage.total_tokens);
python
# pip install openai
from openai import OpenAI

client = OpenAI(
    base_url="https://drouter.web.id/v1",
    api_key="dr-xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
)

r = client.chat.completions.create(
    model="cybernetic",
    messages=[{"role": "user", "content": "Halo."}],
)
print(r.choices[0].message.content)
Kompatibel OpenAI

Karena formatnya identik, library resmi OpenAI (Python, Node, Go, .NET) bisa dipakai langsung - cukup arahkan base_url ke DRouter.

05 Daftar model

Dua model, satu key. Keduanya jalan di atas pool upstream yang sama, jadi kalau satu jalur sedang lambat, request otomatis pindah jalur.

GET cybernetic Model utama. Seimbang - penalaran, kode, analisis, penulisan. Latensi 3-7 detik tipikal.
GET unrestmes Varian tanpa penolakan. Untuk prompt yang ditolak model lain. Latensi sedikit lebih tinggi.
bash
curl https://drouter.web.id/v1/models \
  -H "Authorization: Bearer $DROUTER_KEY"
Nama model internal tidak pernah keluar

Response selalu memakai nama publik (cybernetic / unrestmes). Routing internal, nama provider, dan biaya upstream tidak pernah terlihat dari sisi client.

06 Cek pemakaian

Endpoint /api/me mengembalikan status key plus statistik pemakaian. Login dashboard juga pakai endpoint ini.

bash
curl https://drouter.web.id/api/me \
  -H "Authorization: Bearer $DROUTER_KEY"
json
{
  "key_masked": "dr-KouZ...pyvx",
  "plan": "plus",
  "models": ["unrestmes", "cybernetic"],
  "rpm_cap": 30,
  "ip_lock": "",
  "expired": false,
  "days_left": 5,
  "hours_left": 11,
  "usage": {
    "today": { "requests": 8, "ok": 8, "failed": 0, "total_tokens": 960 },
    "totals": { "requests": 8, "total_tokens": 960 },
    "series": [ { "day": "2026-10-29", "requests": 8, "total_tokens": 960 } ]
  }
}

Versi manusiawinya ada di dashboard - masukkan key, langsung lihat sisa masa aktif, chart 14 hari, dan tabel detail.

07 Penanganan error

Semua error mengembalikan JSON dengan bentuk konsisten: {"error": {"message": "...", "type": "..."}}.

200OK Request berhasil. Cek choices[0].message.content.
400invalid_request Body bukan JSON valid, atau field wajib tidak ada. Contoh: {"error":{"message":"invalid json body","type":"invalid_request"}}
401auth_error Header Authorization tidak ada atau key tidak dikenali. Cek format: harus Bearer dr-....
403auth_error Key valid tapi tidak boleh dipakai: kedaluwarsa, disuspend, IP tidak cocok, atau model tidak ada di paket. Pesan error menyebutkan yang mana.
429rate_limit_error Lewat batas RPM. Tunggu satu menit, atau naikkan paket. Pesan menyebutkan batasnya: rate limit exceeded (30 rpm).
502upstream_error Semua jalur upstream gagal merespons. Ini sisi kami, bukan key kamu - coba lagi beberapa detik. Cek status page kalau berulang.

Contoh penanganan retry

python
import time, requests

def chat(key, payload, tries=3):
    for i in range(tries):
        r = requests.post(
            "https://drouter.web.id/v1/chat/completions",
            headers={"Authorization": f"Bearer {key}"},
            json=payload, timeout=120,
        )
        if r.status_code == 200:
            return r.json()
        if r.status_code == 429:
            time.sleep(60)          # tunggu jendela RPM berikutnya
            continue
        if r.status_code == 502:
            time.sleep(2 * (i + 1)) # upstream sibuk, backoff
            continue
        raise SystemExit(f"HTTP {r.status_code}: {r.text[:300]}")
    raise SystemExit("gagal setelah beberapa percobaan")

08 Rate limit

Batas dihitung per key, per menit (RPM). Jendelanya bergulir - bukan reset di menit bulat.

trial10 rpm Paket percobaan. Cukup untuk uji integrasi.
basic20 rpm Pemakaian pribadi ringan.
plus30 rpm Pemakaian harian aktif.
pro40 rpm Beban produksi kecil sampai menengah.
Praktik aman

Kalau kamu menjalankan beberapa worker paralel, hitung total RPM gabungan - batasnya per key, bukan per proses. Untuk batch besar, beri jeda antar request daripada menembak sekaligus.

09 FAQ

Apakah kompatibel dengan library OpenAI?

Ya. Format request dan response identik dengan OpenAI Chat Completions. Library resmi OpenAI (Python, Node, Go, .NET) bisa dipakai langsung - cukup ganti base_url ke https://drouter.web.id/v1 dan api_key ke key DRouter kamu.

Kenapa response tidak streaming?

Parameter stream diabaikan - response selalu dikirim utuh. Ini disengaja: jalur upstream memakai fallback berurutan, jadi streaming belum bisa dijamin konsisten. Kirim request, tunggu, terima hasil lengkap.

Dapat error 502, apa yang salah?

502 berarti semua jalur upstream gagal merespons - masalah di sisi kami, bukan key kamu. Coba lagi setelah beberapa detik. Kalau berulang, cek status page untuk lihat kondisi live.

Bagaimana cara ganti key kalau bocor?

Hubungi bot Telegram. Key lama akan disuspend dan key baru diterbitkan dengan sisa masa aktif yang sama.

Bisa dipakai untuk produksi?

Bisa. Yang perlu diperhatikan: response tidak streaming, dan latensi tipikal 3-7 detik. Untuk beban tinggi, sesuaikan jumlah worker dengan batas RPM paket kamu.

Apakah ada batas token per hari?

Tidak ada batas token harian. Yang dibatasi cuma kecepatan request (RPM). Pemakaian token dicatat untuk statistik, bukan untuk memotong akses.

Buka dashboard -> Ambil API key