Perubahan model
kenari mengumumkan setiap perubahan pada daftar model dan harganya: model baru, model yang dihapus, harga yang berubah, diskon yang mulai atau berakhir, perubahan harga yang sudah dijadwalkan, dan model yang akan dihentikan. Kamu bisa membaca perubahan ini di halaman web, di channel Telegram, atau lewat endpoint publik yang bisa dipanggil berkala oleh skrip atau agen. Ketiganya menampilkan perubahan yang sama.
Yang dihitung sebagai perubahan
Section titled “Yang dihitung sebagai perubahan”kind | Yang terjadi |
|---|---|
added | Ada model baru di daftar. |
removed | Sebuah model hilang dari daftar. |
price_changed | Harga model berubah, atau model menjadi gratis atau tidak lagi gratis. |
discount_started | Harga pasar model sekarang di atas harga kenari pada sisi input atau output, padahal sebelumnya tidak. |
discount_ended | Harga pasar tidak lagi di atas harga kenari pada suatu sisi. |
price_scheduled | Perubahan harga dijadwalkan, lengkap dengan tanggal berlakunya. |
sunset_scheduled | Sebuah model dijadwalkan berhenti, lengkap dengan tanggalnya. |
Harga pasar adalah harga pembanding yang ditampilkan GET /api/public/pricing di samping harga kenari. Lihat Model & harga.
Perubahan yang bukan soal harga, misalnya model yang menjadi khusus pelanggan, tidak diumumkan.
Kapan perubahan muncul
Section titled “Kapan perubahan muncul”Sebuah perubahan baru diumumkan setelah kenari yakin perubahan itu nyata. Daftar diperiksa setiap 5 menit.
kind | Muncul |
|---|---|
price_changed, discount_started, discount_ended | Setelah perubahan bertahan sekitar 10 menit. |
added | Setelah model terdaftar selama sekitar satu jam. |
removed | Setelah model hilang selama sekitar satu jam. |
price_scheduled, sunset_scheduled | Langsung, karena tanggalnya adalah beritanya. |
Perubahan yang cepat kembali seperti semula tidak pernah diumumkan. Harga yang salah ketik dan diperbaiki dalam 10 menit tidak muncul, dan model yang hilang beberapa menit lalu kembali tidak dilaporkan sebagai dihapus. Jika harga berubah dari A ke B lalu ke C dalam 10 menit, yang diumumkan adalah perubahan dari A ke C.
Model yang sudah diumumkan lewat sunset_scheduled tetap mendapat entri removed di feed saat benar-benar hilang dari daftar. Channel Telegram tidak mengumumkannya untuk kedua kalinya.
Tempat membacanya
Section titled “Tempat membacanya”- Halaman kenari.id/models/changes menampilkan daftar perubahan. Kamu tidak perlu login.
- Channel Telegram t.me/kenari_updates menerima perubahan yang sama. Postingannya berbahasa Inggris, paling banyak satu postingan untuk setiap pemeriksaan. Setiap postingan mengelompokkan perubahan menurut jenisnya, dengan harga dalam Rupiah per 1M token dan tanggal dalam WIB. Perubahan harga menampilkan persentase perubahannya, baris diskon menampilkan harga pasar pembandingnya, dan model yang akan dihentikan atau sudah dihapus menyebut penggantinya bila ada. Postingan yang terlalu panjang dipecah menjadi beberapa pesan.
GET /v1/models/changesmengembalikan perubahan dalam bentuk JSON.
Endpoint
Section titled “Endpoint”GET /v1/models/changes
Endpoint ini publik. Kamu tidak butuh API key, dan browser bisa memanggilnya dari origin mana pun (CORS terbuka). Response bisa di-cache selama 30 detik, jadi memanggil lebih sering dari itu mengembalikan jawaban yang sama.
Request
Section titled “Request”| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
since | integer | Tidak | Waktu unix dalam detik. Hanya kembalikan perubahan yang dikonfirmasi pada atau setelah saat ini. Bawaannya 0, artinya tanpa batas bawah. |
limit | integer | Tidak | Jumlah perubahan yang dikembalikan, dari 1 sampai 200. Bawaannya 50. Nilai di luar rentang dipindahkan ke ujung rentang yang terdekat. |
Response
Section titled “Response”Response berupa daftar: {"object": "list", "channel": ..., "data": [...]}.
| Field | Tipe | Keterangan |
|---|---|---|
object | string | Selalu list. |
channel | string atau null | Handle Telegram publik yang menerima perubahan yang sama, misalnya @kenari_updates. null bila tidak ada. |
data | array | Perubahan, yang terbaru lebih dulu menurut confirmed_at. Kosong bila tidak ada apa pun pada atau setelah since. |
Setiap item di data punya field berikut:
| Field | Tipe | Keterangan |
|---|---|---|
model | string | Id model, sama seperti di GET /v1/models. |
kind | string | Salah satu jenis di Yang dihitung sebagai perubahan. |
old | object, integer, atau null | Keadaan sebelum perubahan. Bentuknya bergantung pada kind. Lihat Old dan new menurut jenis. |
new | object, integer, atau null | Keadaan setelah perubahan, dengan bentuk yang sama seperti old. |
effective_at | integer atau null | Waktu unix dalam detik saat perubahan terjadwal berlaku. Terisi untuk price_scheduled dan sunset_scheduled, null untuk jenis lainnya. |
detected_at | integer | Waktu unix dalam detik saat kenari pertama kali melihat perubahan. |
confirmed_at | integer | Waktu unix dalam detik saat perubahan tampil di daftar ini. Untuk perubahan terjadwal nilainya sama dengan detected_at. Sekitar 10 menit kemudian untuk perubahan harga dan diskon, dan sekitar satu jam kemudian untuk added dan removed. |
successor | string atau null | Model yang ditetapkan sebagai pengganti model ini, untuk sunset_scheduled dan removed. null untuk jenis lainnya. Adanya pengganti tidak dengan sendirinya berarti request dialihkan ke model itu. |
{ "object": "list", "channel": "@kenari_updates", "data": [ { "model": "step-3-7-flash", "kind": "price_changed", "old": { "free": false, "price_in": 1000000000, "price_out": 4000000000, "image": null }, "new": { "free": false, "price_in": 1200000000, "price_out": 4000000000, "image": null }, "effective_at": null, "detected_at": 1791529200, "confirmed_at": 1791532800, "successor": null } ]}Old dan new menurut jenis
Section titled “Old dan new menurut jenis”Harga berupa bilangan bulat dalam micro-Rupiah, dengan Rp 1 sama dengan 1.000.000 micro-Rupiah. Harga token berlaku per 1 juta token, jadi 1200000000 berarti Rp 1.200 per 1 juta token. Lihat Cara penagihan.
Objek harga. Dipakai oleh added, removed, price_changed, dan price_scheduled. Selalu punya empat field:
| Field | Keterangan |
|---|---|
free | true bila model gratis. |
price_in | Harga input per 1 juta token. |
price_out | Harga output per 1 juta token. |
image | Harga per gambar, untuk model yang dihargai per gambar. |
Field harga bernilai null bila model tidak punya harga jenis itu, misalnya image pada model chat.
Objek diskon. Dipakai oleh discount_started dan discount_ended. Punya field in untuk sisi input, field out untuk sisi output, atau keduanya. Hanya sisi yang diskonnya mulai atau berakhir yang ada. Setiap sisi berbentuk {"price": ..., "market": ...}:
| Field | Keterangan |
|---|---|
price | Harga kenari per 1 juta token pada sisi itu. |
market | Harga pasar per 1 juta token pada sisi itu, atau null bila tidak ada. |
Bentuk menurut jenis:
kind | old | new | effective_at |
|---|---|---|---|
added | null | Objek harga. | null |
removed | Objek harga sebelum model hilang. | null | null |
price_changed | Objek harga sebelumnya. | Objek harga sesudahnya. | null |
discount_started | Objek diskon sebelumnya. | Objek diskon sesudahnya, dengan market di atas price. | null |
discount_ended | Objek diskon sebelumnya, dengan market di atas price. | Objek diskon sesudahnya. | null |
price_scheduled | Objek harga dengan harga hari ini. | Objek harga dengan harga yang berlaku mulai effective_at. | Waktu unix dalam detik saat harga baru berlaku. |
sunset_scheduled | Waktu penghentian sebelumnya dalam detik unix, atau null bila belum pernah diatur. | Waktu penghentian dalam detik unix. | Waktu penghentian yang sama. |
Contoh
Section titled “Contoh”Panggilan pertama mengembalikan perubahan terbaru. Panggilan berikutnya memakai since agar hanya mendapat yang baru.
curl "https://kenari.id/v1/models/changes?limit=20"
curl "https://kenari.id/v1/models/changes?since=1791532800"JavaScript
Section titled “JavaScript”Loop ini memanggil endpoint setiap 10 menit. Ia menyimpan confirmed_at terbaru yang pernah dilihat dan memakainya sebagai since pada panggilan berikutnya.
let since = 0;const seen = new Set();
async function poll() { const response = await fetch(`https://kenari.id/v1/models/changes?since=${since}&limit=200`); if (!response.ok) return; const { data } = await response.json();
// Yang terbaru lebih dulu, jadi dibaca dari belakang agar perubahan tertua diproses lebih dulu. for (const change of [...data].reverse()) { const key = `${change.confirmed_at}:${change.model}:${change.kind}`; if (seen.has(key)) continue; seen.add(key); console.log(change.kind, change.model, change.old, "->", change.new); } if (data.length > 0) since = data[0].confirmed_at;}
await poll();setInterval(poll, 10 * 60 * 1000);since ikut menghitung detiknya sendiri, jadi perubahan terbaru muncul sekali lagi pada panggilan berikutnya. Set seen membuangnya.
Mengapa since memakai waktu konfirmasi
Section titled “Mengapa since memakai waktu konfirmasi”since dan urutan daftar memakai confirmed_at, yaitu saat perubahan tampil di daftar, bukan detected_at. Sebuah perubahan dilihat lebih dulu, lalu dikonfirmasi 10 menit atau satu jam kemudian. Jika since memakai waktu pertama kali dilihat, perubahan yang dilihat sesaat sebelum polling terakhirmu dan dikonfirmasi sesaat sesudahnya akan tampak lebih lama dari since-mu, dan kamu tidak akan pernah menerimanya. Sebuah perubahan mendapat confirmed_at tepat saat ia tampil di daftar, jadi nilainya tidak pernah lebih lama dari polling yang belum memilikinya. Poller yang memakai confirmed_at terbaru yang pernah dilihat sebagai since karena itu tidak melewatkan perubahan.
detected_at tetap ada di setiap item, sebagai waktu perubahan itu pertama kali terjadi.
Jika lebih dari limit perubahan dikonfirmasi di antara dua polling, hanya limit yang terbaru yang dikembalikan. Pakai limit=200 dan panggil minimal sekali dalam satu jam.
since atau limit yang bukan bilangan bulat mendapat error 400. Error lainnya ada di Error.