Pemakaian
Baca pemakaian dan biaya akunmu dari skrip atau agen: total per model, deret per hari, atau log tiap request. Endpoint ini khusus kenari dan tidak punya padanan di OpenAI maupun Anthropic. Angkanya sama dengan halaman Pemakaian di dashboard.
GET /v1/usageGET /v1/usage/dailyGET /v1/usage/logKetiganya membutuhkan API key di header Authorization. Key tanpa pembatasan membaca pemakaian seluruh akun, dari semua API key di akun itu. Lihat Siapa bisa membaca apa.
Request
Section titled “Request”Ketiga endpoint menerima parameter query dan tidak punya body. Semua parameter opsional. Parameter yang tidak dikenal diabaikan. Kalau parameter diulang, nilai pertama yang dipakai.
| Parameter | Tipe | Endpoint | Deskripsi |
|---|---|---|---|
start | integer | semua | Awal jendela, dalam detik Unix, termasuk batasnya. |
end | integer | semua | Akhir jendela, dalam detik Unix, termasuk batasnya. Nilai di masa depan dianggap sekarang. |
range | string | semua | Jendela preset yang berakhir sekarang: today (sejak 00:00 UTC), 24h, 7d, atau 30d. Default-nya 30d. |
model | string | semua | Hanya model dengan id persis ini. |
api_key_id | string | semua | Hanya request yang dibuat dengan id key ini. Untuk key terbatas, lihat Siapa bisa membaca apa. |
billing_kind | string | /v1/usage/log | Hanya jenis penagihan ini: payg, plan, coupon, token_alloc, free, atau byok. |
page | integer | /v1/usage/log | Nomor halaman, dimulai dari 0. Default-nya 0. |
limit | integer | /v1/usage/log | Jumlah request per halaman. Default-nya 50. Nilai di luar 1 sampai 200 dipindahkan ke batas terdekat, tidak ditolak. |
Aturan jendela
Section titled “Aturan jendela”Ketiga endpoint menentukan jendela dengan cara yang sama.
- Tanpa
start,end, ataurange, jendelanya 30 hari terakhir. startdanendmenang atasrange. Kalau salah satunya ada,rangediabaikan, bahkan kalau nilainya tidak valid.- Dengan
startsaja, jendela berakhir sekarang. Denganendsaja, jendela dimulai 30 hari sebelumend. enddibatasi sampai sekarang.startdanendtidak boleh negatif, danstarttidak boleh setelahend./v1/usagedan/v1/usage/dailymenerima jendela yang menyentuh paling banyak 366 hari UTC. Jendela yang lebih panjang menghasilkan400./v1/usage/logtidak punya batas itu, tetapi lihat batas kedalaman di bawah.
Response selalu mengulang start dan end yang dipakai, sehingga kamu bisa melihat jendela yang sebenarnya.
Jenis penagihan
Section titled “Jenis penagihan”billing_kind menunjukkan apa yang membayar sebuah request.
| Nilai | Arti |
|---|---|
payg | PAYG, dibayar dari saldo. |
plan | Ditanggung kuota paket. |
coupon | Ditanggung kupon. |
token_alloc | Ditanggung alokasi token. |
free | Model gratis. |
byok | Dilayani key BYOK milikmu. |
Semua jumlah berupa integer dalam mikro-Rupiah, yaitu Rupiah dikali 1.000.000. Rp 1 adalah 1000000. Lihat Cara penagihan. Setiap baris punya dua jumlah.
cost_micro_idradalah jumlah yang dipotong dari saldo kamu. Pemakaian paket, kupon, model gratis, dan BYOK bernilai0di sini, karena tidak dibayar dari saldo.catalog_micro_idradalah nilai pemakaian yang sama menurut harga daftar model. Dengan ini kamu bisa melihat nilai yang kamu dapat dari paket, kupon, model gratis, atau key BYOK, yang tagihannya bisa lebih rendah dari harga daftar atau0.
Ringkasan
Section titled “Ringkasan”GET /v1/usage mengembalikan satu baris per model dan jenis penagihan, diurutkan dari cost_micro_idr terbesar, ditambah baris total. Pemakaian paket dilaporkan sebagai plan. Request tanpa jenis penagihan tercatat dilaporkan sebagai payg.
| Field | Tipe | Deskripsi |
|---|---|---|
object | string | Selalu usage.summary. |
start | integer | Awal jendela, dalam detik Unix. |
end | integer | Akhir jendela, dalam detik Unix. |
data | array | Satu baris per model dan jenis penagihan. Kosong kalau tidak ada pemakaian. |
data[].model | string | Id model. |
data[].billing_kind | string | Salah satu jenis penagihan di atas. |
data[].requests | integer | Jumlah request. |
data[].prompt_tokens | integer | Token input. |
data[].completion_tokens | integer | Token output. |
data[].cached_prompt_tokens | integer | Token input yang dibaca dari cache. |
data[].cache_write_prompt_tokens | integer | Token input yang ditulis ke cache. |
data[].cost_micro_idr | integer | Jumlah yang dipotong dari saldo, dalam mikro-Rupiah. |
data[].catalog_micro_idr | integer | Nilai menurut harga daftar, dalam mikro-Rupiah. |
total | object | Tujuh penghitung yang sama, dijumlahkan dari semua baris. |
{ "object": "usage.summary", "start": 1788300000, "end": 1790892000, "data": [ { "model": "deepseek-v4-flash", "billing_kind": "payg", "requests": 120, "prompt_tokens": 480000, "completion_tokens": 96000, "cached_prompt_tokens": 200000, "cache_write_prompt_tokens": 0, "cost_micro_idr": 15400000, "catalog_micro_idr": 15400000 }, { "model": "step-3-7-flash:free", "billing_kind": "free", "requests": 40, "prompt_tokens": 52000, "completion_tokens": 18000, "cached_prompt_tokens": 0, "cache_write_prompt_tokens": 0, "cost_micro_idr": 0, "catalog_micro_idr": 900000 } ], "total": { "requests": 160, "prompt_tokens": 532000, "completion_tokens": 114000, "cached_prompt_tokens": 200000, "cache_write_prompt_tokens": 0, "cost_micro_idr": 15400000, "catalog_micro_idr": 16300000 }}Deret harian
Section titled “Deret harian”GET /v1/usage/daily mengembalikan satu baris per hari UTC di jendela, dari yang terlama. Hari tanpa pemakaian menjadi baris berisi nol, sehingga deretnya tidak berlubang. Filter model dan api_key_id berlaku.
| Field | Tipe | Deskripsi |
|---|---|---|
object | string | Selalu usage.daily. |
start | integer | Awal jendela, dalam detik Unix. |
end | integer | Akhir jendela, dalam detik Unix. |
data | array | Satu baris per hari UTC. |
data[].date | string | Hari UTC, dalam format YYYY-MM-DD. |
data[].requests | integer | Jumlah request pada hari itu. |
data[].cost_micro_idr | integer | Jumlah yang dipotong dari saldo pada hari itu, dalam mikro-Rupiah. |
{ "object": "usage.daily", "start": 1790287200, "end": 1790892000, "data": [ { "date": "2026-09-24", "requests": 18, "cost_micro_idr": 2100000 }, { "date": "2026-09-25", "requests": 0, "cost_micro_idr": 0 }, { "date": "2026-09-26", "requests": 7, "cost_micro_idr": 950000 } ]}Log request
Section titled “Log request”GET /v1/usage/log mengembalikan tiap request, dari yang terbaru. Semua filter didukung, termasuk billing_kind. Pemakaian paket dilaporkan sebagai plan.
| Field | Tipe | Deskripsi |
|---|---|---|
object | string | Selalu list. |
start | integer | Awal jendela, dalam detik Unix. |
end | integer | Akhir jendela, dalam detik Unix. |
data | array | Request di halaman ini. |
data[].created_at | integer | Waktu request dibuat, dalam detik Unix. |
data[].model | string | Id model. |
data[].vendor | string | Pembuat model. |
data[].api_key_id | string atau null | Id key yang membuat request. null kalau tidak ada. |
data[].billing_kind | string | Salah satu jenis penagihan di atas. |
data[].prompt_tokens | integer | Token input. |
data[].completion_tokens | integer | Token output. |
data[].cached_prompt_tokens | integer | Token input yang dibaca dari cache. |
data[].cache_write_prompt_tokens | integer | Token input yang ditulis ke cache. |
data[].cost_micro_idr | integer | Jumlah yang dipotong dari saldo, dalam mikro-Rupiah. |
data[].catalog_micro_idr | integer | Nilai menurut harga daftar, dalam mikro-Rupiah. |
page | integer | Nomor halaman yang dipakai. |
limit | integer | Ukuran halaman yang dipakai, setelah dibatasi. |
has_more | boolean | true kalau masih ada halaman berikutnya. |
total | integer | Jumlah request yang cocok dengan filter di seluruh jendela, bukan hanya halaman ini. |
{ "object": "list", "start": 1788300000, "end": 1790892000, "data": [ { "created_at": 1790891000, "model": "deepseek-v4-flash", "vendor": "DeepSeek", "api_key_id": "a1b2c3d4", "billing_kind": "payg", "prompt_tokens": 4200, "completion_tokens": 310, "cached_prompt_tokens": 2000, "cache_write_prompt_tokens": 0, "cost_micro_idr": 128000, "catalog_micro_idr": 128000 } ], "page": 0, "limit": 50, "has_more": true, "total": 120}page dikali limit tidak boleh lebih dari 10.000. Halaman yang lebih dalam menghasilkan 400. Untuk membaca lebih jauh ke belakang, persempit jendela dengan start dan end, lalu baca per potongan.
Siapa bisa membaca apa
Section titled “Siapa bisa membaca apa”- Key tanpa pembatasan membaca pemakaian seluruh akun, dan bisa mempersempitnya dengan
api_key_id. - Key dengan batas model, batas pengeluaran, atau batas token adalah key terbatas. Key itu hanya membaca pemakaian key-nya sendiri. Kosongkan
api_key_id, atau isi dengan id key itu sendiri. Id lain menghasilkan400. - API key dibagikan tidak bisa membaca pemakaian sama sekali. Hasilnya
403danshared_key_not_allowed.
Lihat Autentikasi & API key untuk cara membatasi key.
Ketiga endpoint berbagi satu batas 60 request per menit untuk tiap akun, key mana pun yang dipakai. Kalau melewati batas, request gagal dengan 429 dan rate_limit_exceeded, tanpa header Retry-After. Tunggu beberapa detik lalu coba lagi. Batas ini dihitung terpisah dari batas request chat, jadi membaca pemakaian tidak menghabiskan request chatmu. Lihat Batas laju.
Contoh
Section titled “Contoh”curl "https://kenari.id/v1/usage?range=7d" \ -H "Authorization: Bearer $KENARI_API_KEY"Deret harian untuk satu jendela, dan log yang difilter ke request PAYG:
curl "https://kenari.id/v1/usage/daily?start=1788300000&end=1790892000" \ -H "Authorization: Bearer $KENARI_API_KEY"
curl "https://kenari.id/v1/usage/log?billing_kind=payg&limit=100&page=0" \ -H "Authorization: Bearer $KENARI_API_KEY"Python
Section titled “Python”Skrip ini menjumlahkan pengeluaran bulan ini per model. Skrip membaca ringkasan sejak hari pertama bulan ini dalam UTC, lalu menjumlahkan semua jenis penagihan tiap model.
import osfrom collections import defaultdictfrom datetime import datetime, timezone
import requests
now = datetime.now(timezone.utc)month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
response = requests.get( "https://kenari.id/v1/usage", headers={"Authorization": f"Bearer {os.environ['KENARI_API_KEY']}"}, params={"start": int(month_start.timestamp())},)response.raise_for_status()usage = response.json()
per_model = defaultdict(int)for row in usage["data"]: per_model[row["model"]] += row["cost_micro_idr"]
for model, micro in sorted(per_model.items(), key=lambda item: -item[1]): print(f"{model}: Rp {micro / 1_000_000:,.0f}")print("Total:", f"Rp {usage['total']['cost_micro_idr'] / 1_000_000:,.0f}")JavaScript
Section titled “JavaScript”const now = new Date();const monthStart = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1) / 1000;
const response = await fetch(`https://kenari.id/v1/usage?start=${monthStart}`, { headers: { Authorization: `Bearer ${process.env.KENARI_API_KEY}` },});if (!response.ok) throw new Error(await response.text());const usage = await response.json();
const perModel = {};for (const row of usage.data) { perModel[row.model] = (perModel[row.model] ?? 0) + row.cost_micro_idr;}
for (const [model, micro] of Object.entries(perModel).sort((a, b) => b[1] - a[1])) { console.log(model, Math.round(micro / 1_000_000));}Penagihan
Section titled “Penagihan”Membaca pemakaian gratis. Lihat Cara penagihan.
| Status | Kode | Kapan |
|---|---|---|
| 400 | bad_request | Parameter tidak valid: nilai yang bukan integer, start atau end negatif, start setelah end, range yang bukan salah satu dari empat preset (kalau start dan end tidak diisi), jendela lebih dari 366 hari di /v1/usage atau /v1/usage/daily, billing_kind yang bukan salah satu dari enam nilai, page negatif, page dikali limit lebih dari 10.000, atau api_key_id yang bukan id key terbatas itu sendiri. Field param menyebut nama parameternya dan message menjelaskan masalahnya. |
| 401 | Tidak ada | Key tidak ada, tidak valid, atau sudah kedaluwarsa. Body-nya pesan teks singkat, bukan JSON. |
| 403 | shared_key_not_allowed | Key adalah API key dibagikan. |
| 429 | rate_limit_exceeded | Lebih dari 60 request pemakaian dalam semenit untuk akun. Tidak ada header Retry-After. |
| 500 | internal_error | Pembacaan pemakaian gagal di kenari. Coba lagi sekali. |
Body-nya format OpenAI. Pada 400, type berisi invalid_request_error dan param berisi nama parameter. Lihat Error untuk format error dan kode lainnya.